simplify childProcess
This commit is contained in:
+1
-1
@@ -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"
|
||||
|
||||
+69
-119
@@ -53,141 +53,91 @@ inline std::optional<DeadProc> 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
|
||||
}
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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<PendingCmd&>(ccmd);
|
||||
assert(c.in==0 && "Capturing redirected output");
|
||||
|
||||
c.in = PIPE;
|
||||
|
||||
return detach(c);
|
||||
}
|
||||
|
||||
inline Proc detachRedirOut(const PendingCmd& ccmd)
|
||||
{
|
||||
auto& c = const_cast<PendingCmd&>(ccmd);
|
||||
|
||||
+52
-28
@@ -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<fs::path> 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<fs::path> preprocess_and_compare()
|
||||
bool preprocess_and_compare()
|
||||
{
|
||||
Cmd preprocess(
|
||||
src_type == SrcType::C ? CC : CXX,
|
||||
@@ -233,16 +238,33 @@ optional<fs::path> 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<fs::path> 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<fs::path> 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,8 +356,11 @@ void compile_src_file()
|
||||
|
||||
|
||||
if( !compile() ) // if failed to compile
|
||||
{
|
||||
fs::remove(bin);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void print_usage()
|
||||
|
||||
Regular → Executable
+1
@@ -1,3 +1,4 @@
|
||||
#!/usr/local/bin/cppipe
|
||||
// Test cppipe functions
|
||||
|
||||
#include <cppipe/commands.hpp>
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user