check if recompiling is needed by preprocessing

This commit is contained in:
vrd
2024-03-18 09:50:04 +02:00
committed by Venelin
parent 097738cf64
commit d88212f6e7
6 changed files with 162 additions and 58 deletions
+131 -41
View File
@@ -2,15 +2,43 @@
#include <cstring>
#include <filesystem>
#include <iostream>
#include <fstream>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include "commands.hpp"
using namespace std;
namespace fs = std::filesystem;
static fs::path find_path_to_cpp(string_view file); // find the cpp to run, if it doesn't exist, exit program
static fs::path get_cache_path(const fs::path& file); // find the path of the cache for the given file path
static bool compile_file(const fs::path& file, const fs::path& cache, bool debug); // return true on success
struct MappedFile // todo: move to utils
{
// ~MappedFile()
// {
// munmap(data, len);
// }
char* data;
unsigned len;
};
// find the cpp to run, if it doesn't exist, exit program
static fs::path find_path_to_cpp(string_view src_file);
// find the path of the cache for the given src_file path
static fs::path get_cache_dir_path(const fs::path& src_file);
// map file in memory with write persmissions
static MappedFile mapfile_for_writing(const fs::path& file);
// check weather a src file or it's headers have changed
static bool is_src_file_changed(const fs::path& src_file, const fs::path& cache_dir);
// returns bin path
static fs::path compile_file(const fs::path& src_file, const fs::path& cache_dir);
static const char DEBUG_PREFIX[] = "__DBG";
static bool debug = false;
int main(int argc, char* argv[])
{
@@ -23,14 +51,13 @@ int main(int argc, char* argv[])
{
cout << "Usage: cppipe [-g] FILE [ARGUMENTS]...\n"
<< "Compile and run C++ source FILE that uses the cppipe library.\n"
"Pass the ARGUMENTS to he compiled binary.\n"
"The binaries are cached and recompiled only if the source is newer.\n"
"Pass the ARGUMENTS to the compiled binary.\n"
"The binaries are cached and recompiled only if the source or it's headers have changed.\n"
"-g debug the binary, asserts are also enabled\n";
return 0;
}
bool debug = false;
int file_arg = 1;
if( !strcmp(argv[1], "-g") )
{
@@ -44,18 +71,14 @@ int main(int argc, char* argv[])
file_arg = 2;
}
const fs::path file = find_path_to_cpp( argv[file_arg] );
const fs::path src_file = find_path_to_cpp( argv[file_arg] );
fs::path cache( get_cache_path(file) ); // cache bins to avoid recompiles
fs::path cache_dir( get_cache_dir_path(src_file) ); // cache bins to avoid recompiles
if(debug)
cache += "_dbg";
// Compile the src
fs::path bin = compile_file(src_file, cache_dir);
// Compile the cpp
if( !compile_file(file, cache, debug) )
return 1;
// Run the file without forking
// Run the src file without forking
Cmd run;
if(debug) // debug it with gdb
{
@@ -63,17 +86,17 @@ int main(int argc, char* argv[])
run += "--args";
}
run += cache.c_str();
run += bin.c_str();
for(int i = file_arg+1; i < argc; ++i)
run += argv[i];
exec(run);
}
static fs::path find_path_to_cpp(string_view file)
static fs::path find_path_to_cpp(string_view src_file)
{
if(fs::exists(file)) // found relative to CWD
if(fs::exists(src_file)) // found relative to CWD
{
return file;
return src_file;
}
// search files on CPPIPEPATH
@@ -90,7 +113,7 @@ static fs::path find_path_to_cpp(string_view file)
{
for(const fs::directory_entry& e: fs::directory_iterator(path_entry))
{
if(fs::is_regular_file(e) && e.path().filename() == file)
if(fs::is_regular_file(e) && e.path().filename() == src_file)
{
return e;
}
@@ -103,60 +126,127 @@ static fs::path find_path_to_cpp(string_view file)
}
// Couln't find the cpp
cerr << "File: " << file << " doesn't exist\n";
cerr << "File: " << src_file << " doesn't exist\n";
exit(1);
}
static fs::path get_cache_path(const fs::path& file)
static fs::path get_cache_dir_path(const fs::path& src_file)
{
fs::path cache;
fs::path cache_dir;
if(char* xdg_cache = getenv("XDG_CACHE_HOME"))
{
cache = xdg_cache;
cache /= "cppipe";
cache_dir = xdg_cache;
cache_dir /= "cppipe";
}
else
{
char* home( getenv("HOME") );
cache = home;
cache /= ".cache/cppipe";
cache_dir = home;
cache_dir /= ".cache/cppipe";
}
cache += fs::absolute(file);
fs::create_directories(cache.parent_path());
return cache;
cache_dir += fs::canonical( src_file ).parent_path();
fs::create_directories(cache_dir);
return cache_dir;
}
static bool compile_file(const fs::path& file, const fs::path& cache, bool debug)
static MappedFile mapfile_for_writing(const fs::path& file)
{
fd_t fd = open(file.c_str(), O_RDWR);
MappedFile res;
res.len = lseek(fd, 0, SEEK_END);
res.data = (char*)mmap(nullptr, res.len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
close(fd);
return res;
}
// preprocess the file and comapre it to the old pped version
static bool is_src_file_changed(const fs::path& src_file, const fs::path& cache_dir)
{
Cmd preprocess(
"g++",
"-E", // preprocess only
"-P", // don't generate linemarkers in the output to reduce file size
src_file.c_str()
);
if(!debug)
preprocess += "-DNDEBUG";
fs::path old_pp_path = cache_dir / (debug ? DEBUG_PREFIX : "") += src_file.stem() += ".ii";
string new_pp = $(preprocess);
if( fs::exists(old_pp_path) ) // todo: clean up if else blocks
{
if( fs::file_size(old_pp_path) == new_pp.size() )
{
MappedFile old_pp = mapfile_for_writing(old_pp_path);
if( !memcmp(old_pp.data, &new_pp[0], old_pp.len) ) // unchanged
{
return false;
}
else
{
memcpy(old_pp.data, &new_pp[0], old_pp.len);
munmap(old_pp.data, old_pp.len);
return true;
}
// todo
// munmap(data, len);
}
else
{
ofstream pp_file(old_pp_path);
pp_file << new_pp;
return true;
}
}
else
{
ofstream pp_file(old_pp_path);
pp_file << new_pp;
return true;
}
return true;
}
static fs::path compile_file(const fs::path& src_file, const fs::path& cache_dir)
{
// Only compile if the source is newer then the bin
error_code ec;
if(last_write_time(file) > last_write_time(cache, ec))
fs::path cache_bin = cache_dir / (debug ? DEBUG_PREFIX : "") += src_file.filename();
if(is_src_file_changed(src_file, cache_dir) || !fs::exists(cache_bin))
{
string preprocessed_file = cache_dir / src_file.stem() += ".ii"; // todo: duplicates with old_pp_path // todo: support C
Cmd compile(
"g++",
"-o", cache.c_str(),
preprocessed_file.c_str(),
"-o", cache_bin.c_str(),
"-pipe", "-std=c++17", "-march=native",
// "-Wall", "-Wextra", "-Wno-parentheses",
file.c_str(),
"-Wall", "-Wextra", "-Wno-parentheses",
"-lcppipe"
);
if(debug)
{
compile.append_args({
"-g",
"-Wall", "-Wextra", "-Wno-parentheses"
"-g"
// "-Wall", "-Wextra", "-Wno-parentheses"
});
}
else
{
compile.append_args({
"-Ofast", "-flto", "-DNDEBUG", "-s"
"-Ofast", "-flto", "-s"
});
}
if( !compile() ) // if failed to compile
return false;
exit(1);
}
return true;
return cache_bin;
}