From 9923192ec91a2bc6e5a4a3fb0292c44da66172b2 Mon Sep 17 00:00:00 2001 From: Venelin Date: Thu, 26 Dec 2024 22:59:26 +0200 Subject: [PATCH] simplify childProcess --- run_tests.sh | 2 +- src/childProcess.inl | 188 ++++++++++++++----------------------- src/commands.hpp | 4 + src/commands.inl | 10 ++ src/cppipe.cpp | 80 ++++++++++------ test/functions_test.cppipe | 1 + todo.txt | 3 + 7 files changed, 140 insertions(+), 148 deletions(-) mode change 100644 => 100755 test/functions_test.cppipe diff --git a/run_tests.sh b/run_tests.sh index 34255c9..a988731 100755 --- a/run_tests.sh +++ b/run_tests.sh @@ -2,7 +2,7 @@ set -e # Test cppipe functions -OKs=$(cppipe test/functions_test.cppipe 2>/dev/null | grep OK | wc -l) +OKs=$(test/functions_test.cppipe 2>/dev/null | grep OK | wc -l) if ! [ $OKs = 13 ] then echo "Functions test failed: EXPECTED 13 OKs, got $OKs" diff --git a/src/childProcess.inl b/src/childProcess.inl index 970fe78..ead5bbb 100644 --- a/src/childProcess.inl +++ b/src/childProcess.inl @@ -53,141 +53,91 @@ inline std::optional check_exited(Proc p) namespace _cppipe { - /* Create a proccess */ - inline Proc create(const char* const argv[], fd_t in, fd_t out, fd_t err) + inline void redirect(fd_t new_fd, fd_t old_fd) { - Proc proc; - proc.in = in; - proc.out = out; - proc.err = err; - - proc.pid = fork(); - if(proc.pid == 0) /* child */ - { - if(in != STDIN_FILENO) - dup2(in, STDIN_FILENO); - - if(out != STDOUT_FILENO) - dup2(out, STDOUT_FILENO); - - if(err != STDERR_FILENO) - dup2(err, STDERR_FILENO); - - exec_or_die(argv); - } - - return proc; - } - - /* Create a process taking input from pipe childIn */ - inline Proc createInRedirected(const char* const argv[], const fd_t childIn[2]) - { - Proc childproc; - childproc.in = childIn[1]; - childproc.out = STDOUT_FILENO; - childproc.err = STDERR_FILENO; - - childproc.pid = fork(); - if(childproc.pid == 0) /* child */ - { - close(childIn[1]); - dup2(childIn[0], STDIN_FILENO); - - exec_or_die(argv); - } - - return childproc; - } - - /* Like createInRedirected but redirect output to a new pipe */ - inline Proc createInOutRedirected(const char* const argv[], const fd_t childIn[2]) - { - fd_t childOut[2]; /* todo: add error #include "processTypes.hpp"*/ - pipe(childOut); - - Proc childproc; - childproc.in = childIn[1]; - childproc.out = childOut[0]; - childproc.err = STDERR_FILENO; - - childproc.pid = fork(); - if(childproc.pid != 0) /* parent */ - { - close(childOut[1]); - } - else - { - close(childIn[1]); - dup2(childIn[0], STDIN_FILENO); - - dup2(childOut[1], STDOUT_FILENO); - - exec_or_die(argv); - } - - return childproc; - } - - inline Proc createCapProcess(const char* const argv[], fd_t in, fd_t err) - { - fd_t childOut[2]; - pipe(childOut); - - Proc proc; - proc.in = in; - proc.out = childOut[0]; - proc.err = err; - - proc.pid = fork(); - if(proc.pid == 0) /* child */ - { - if(in != STDIN_FILENO) - dup2(in, STDIN_FILENO); - - dup2(childOut[1], STDOUT_FILENO); - - if(err != STDERR_FILENO) - dup2(err, STDERR_FILENO); - - exec_or_die(argv); - } - else /* parent */ - { - close(childOut[1]); /* close write side */ - } - - return proc; + if(new_fd != old_fd) + dup2(new_fd, old_fd); } } inline Proc createProcess(const char* const argv[], fd_t in, fd_t out, fd_t err) { - Proc proc; + using _cppipe::redirect; - if(in == PIPE) + bool in_redir = in == PIPE; + bool out_redir = out == PIPE; + bool err_redir = err == PIPE; + + Proc p; + + fd_t childIn[2], childOut[2], childErr[2]; + if(in_redir) { - fd_t childIn[2]; pipe(childIn); - - if(out == PIPE) - proc = _cppipe::createInOutRedirected(argv, childIn); - else - proc = _cppipe::createInRedirected(argv, childIn); - - close(childIn[0]); // parent closes read side + p.in = childIn[1]; } - else if(out == PIPE) - proc = _cppipe::createCapProcess(argv, in, err); - else /* todo: err == PIPE */ - proc = _cppipe::create(argv, in, out, err); + else + p.in = in; - return proc; + if(out_redir) + { + pipe(childOut); + p.out = childOut[0]; + } + else + p.out = out; + + if(err_redir) + { + pipe(childErr); + p.err = childErr[0]; + } + else + p.err = err; + + p.pid = fork(); + if(p.pid == 0) /* child */ + { + /* Close write side */ + if(in_redir) + close(childIn[1]); + + /* Close read side */ + if(out_redir) + close(childOut[0]); + if(err_redir) + close(childErr[0]); + + /* Take pipe as standart in, out, err */ + redirect(in_redir ? childIn[0] : in, STDIN_FILENO); + redirect(out_redir ? childOut[1] : out, STDOUT_FILENO); + redirect(err_redir ? childErr[1] : err, STDERR_FILENO); + + exec_or_die(argv); + } + else /* parent */ + { + /* Close read side */ + if(in_redir) + close(childIn[0]); + + /* Close write side */ + if(out_redir) + close(childOut[1]); + if(err_redir) + close(childErr[1]); + } + + return p; } inline void exec_or_die(const char* const argv[]) { execvp(argv[0], (char* const *)argv); - std::cerr << "Can't execute: " << argv[0] << ' ' << strerror(errno) << std::endl; + std::cerr << "Can't execute command: " << argv[0] << ' ' << strerror(errno) << '\n'; + + /* for(const char* const * arg = argv; *arg != nullptr; ++arg) */ + /* std::cerr << *arg << '\n'; */ _exit(1); // _exit since we are a child } diff --git a/src/commands.hpp b/src/commands.hpp index 049f967..64c4a3c 100644 --- a/src/commands.hpp +++ b/src/commands.hpp @@ -66,6 +66,7 @@ private: bool execed_; friend Proc detach(const PendingCmd&); + friend Proc detachRedirIn(const PendingCmd&); friend Proc detachRedirOut(const PendingCmd&); friend Proc detachRedirInOut(const PendingCmd&); }; @@ -82,6 +83,9 @@ DeadProc run(const PendingCmd&); becomes: cmd.detach() */ Proc detach(const PendingCmd&); +/* Detach but redirect input to a new pipe + * Which can then be read to using write(Proc.in, ...) */ +Proc detachRedirIn(const PendingCmd&); /* Detach but redirect output to a new pipe */ Proc detachRedirOut(const PendingCmd&); /* Also rediredct input */ diff --git a/src/commands.inl b/src/commands.inl index 06efae7..d32f96e 100644 --- a/src/commands.inl +++ b/src/commands.inl @@ -146,6 +146,16 @@ inline Proc detach(const PendingCmd& ccmd) return createProcess(c.cmd.argv.data(), c.in, c.out, c.err); } +inline Proc detachRedirIn(const PendingCmd& ccmd) +{ + auto& c = const_cast(ccmd); + assert(c.in==0 && "Capturing redirected output"); + + c.in = PIPE; + + return detach(c); +} + inline Proc detachRedirOut(const PendingCmd& ccmd) { auto& c = const_cast(ccmd); diff --git a/src/cppipe.cpp b/src/cppipe.cpp index 064eac6..57ecb5e 100644 --- a/src/cppipe.cpp +++ b/src/cppipe.cpp @@ -43,12 +43,12 @@ fs::path find_path_to_src(string_view src_file); // find the path of the cache for the given src_file path fs::path get_cache_dir_path(const fs::path& src_file); -// map file in memory with write persmissions +// map file in memory with write permissions MappedFile mapfile_for_writing(const fs::path& file); // preprocess the src file, compare and overwrite the result to the previous version -// return the path of the preprocessed file if it's different -optional preprocess_and_compare(); +// return whether there was a difference +bool preprocess_and_compare(); // only recompile if changes are present void compile_src_file(); @@ -64,11 +64,12 @@ fs::path HOME; fs::path src_file; SrcType src_type; fs::path cache_dir; +fs::path preprocessed_file; fs::path bin; // cache bins to avoid recompiles // Options bool debug = false; -// just compare timestamps of the source and bin, dont preprocess +// just compare timestamps of the source and bin, don't preprocess bool quick = false; } @@ -82,6 +83,10 @@ int main(int argc, char* argv[]) src_file = find_path_to_src( argv[src_arg] ); src_type = find_src_type( argv[src_arg] ); cache_dir = get_cache_dir_path(src_file); + + preprocessed_file = cache_dir / (debug ? DEBUG_PREFIX : "") += src_file.stem() + += (src_type == SrcType::C ? ".i" : ".ii"); + bin = cache_dir / (debug ? DEBUG_PREFIX : "") += src_file.filename(); // Compile the src @@ -178,7 +183,7 @@ fs::path find_path_to_src(string_view src_file) } } - // Couln't find the src + // Couldn't find the src cerr << "File: " << src_file << " doesn't exist\n"; exit(1); } @@ -212,7 +217,7 @@ MappedFile mapfile_for_writing(const fs::path& file) return res; } -optional preprocess_and_compare() +bool preprocess_and_compare() { Cmd preprocess( src_type == SrcType::C ? CC : CXX, @@ -233,16 +238,33 @@ optional preprocess_and_compare() preprocess += "-xc++"; // treat the file as a .cpp } - // Read source from stdin - preprocess += "-"; - - if(!debug) preprocess += "-DNDEBUG"; - // Preprocessed file from the previous run - fs::path old_pp_path = cache_dir / (debug ? DEBUG_PREFIX : "") += src_file.stem() - += (src_type == SrcType::C ? ".i" : ".ii"); + // Read source from stdin + preprocess += "-"; + + // THIS IS THE RIGHT WAY BUT CURRENTLY PRODUCES A GCC WARNING + // File to preprocess + // fd_t src = open(src_file.c_str(), O_RDONLY); + + // If it begins with #! skip the first line + // char buf[128]; + // int read_count = read(src, &buf, 128); + // if(read_count > 1 && buf[0] == '#' && buf[1] == '!') + // { + // int newline = 0; + // while(buf[newline] != '\n') // out of bounds + // ++newline; + + // lseek(src, newline, SEEK_SET); + // } + // else + // lseek(src, 0, SEEK_SET); + + // Start preprocessing, give the source FD to gcc + // Proc preprocessing = detachRedirOut(preprocess < src); + // close(preprocessing.in); Proc preprocessing = detachRedirInOut(preprocess); @@ -264,36 +286,36 @@ optional preprocess_and_compare() if( !wait(preprocessing) ) // preprocessing failed exit(1); - if( fs::exists(old_pp_path) ) // todo: clean up if else blocks + if( fs::exists(preprocessed_file) ) // todo: clean up if else blocks { - if( fs::file_size(old_pp_path) == new_pp.size() ) + if( fs::file_size(preprocessed_file) == new_pp.size() ) { - MappedFile old_pp = mapfile_for_writing(old_pp_path); - if( !memcmp(old_pp.data, &new_pp[0], old_pp.len) ) // unchanged + MappedFile old_pp = mapfile_for_writing(preprocessed_file); + if( !memcmp(old_pp.data, new_pp.data(), old_pp.len) ) // unchanged { - return nullopt; + return false; } else { memcpy(old_pp.data, &new_pp[0], old_pp.len); munmap(old_pp.data, old_pp.len); - return old_pp_path; + return true; } // todo // munmap(data, len); } else { - ofstream pp_file(old_pp_path); + ofstream pp_file(preprocessed_file); pp_file << new_pp; - return old_pp_path; + return true; } } else { - ofstream pp_file(old_pp_path); + ofstream pp_file(preprocessed_file); pp_file << new_pp; - return old_pp_path; + return true; } } @@ -304,20 +326,19 @@ void compile_src_file() error_code ec; if(fs::last_write_time(src_file) < fs::last_write_time(bin, ec)) { - // Binary is newer then source, dont recompile + // Binary is newer then source, don't recompile return; } } - optional new_preprocessed = preprocess_and_compare(); + bool file_changed = preprocess_and_compare(); // Only compile if the source is newer then the bin - if(new_preprocessed || !fs::exists(bin)) + if(file_changed || !fs::exists(bin)) { - Cmd compile( src_type == SrcType::C ? CC : CXX, - new_preprocessed->c_str(), + preprocessed_file.c_str(), "-o", bin.c_str() ); @@ -335,7 +356,10 @@ void compile_src_file() if( !compile() ) // if failed to compile + { + fs::remove(bin); exit(1); + } } } diff --git a/test/functions_test.cppipe b/test/functions_test.cppipe old mode 100644 new mode 100755 index 0245e48..a932eaa --- a/test/functions_test.cppipe +++ b/test/functions_test.cppipe @@ -1,3 +1,4 @@ +#!/usr/local/bin/cppipe // Test cppipe functions #include diff --git a/todo.txt b/todo.txt index 8b77366..64fa16b 100644 --- a/todo.txt +++ b/todo.txt @@ -1,3 +1,4 @@ +example #!/usr/bin/cppipe description - advantages over manual compile man tips (sigaction SIGCHILD, SIG_IGN, SIG_DFL) @@ -5,6 +6,7 @@ tips (sigaction SIGCHILD, SIG_IGN, SIG_DFL) make sure file descriptors are closed when no longer used cppipe compile options from tft respect CXXFLAGS LDFLAGS +< PendingCmd store files we need to close ? optional exec @@ -20,3 +22,4 @@ uninstall improve debug (the src file shown is the .ii) no optimizations option split +PendingCmd template