simplify childProcess
This commit is contained in:
+1
-1
@@ -2,7 +2,7 @@
|
|||||||
set -e
|
set -e
|
||||||
|
|
||||||
# Test cppipe functions
|
# 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 ]
|
if ! [ $OKs = 13 ]
|
||||||
then
|
then
|
||||||
echo "Functions test failed: EXPECTED 13 OKs, got $OKs"
|
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
|
namespace _cppipe
|
||||||
{
|
{
|
||||||
/* Create a proccess */
|
inline void redirect(fd_t new_fd, fd_t old_fd)
|
||||||
inline Proc create(const char* const argv[], fd_t in, fd_t out, fd_t err)
|
|
||||||
{
|
{
|
||||||
Proc proc;
|
if(new_fd != old_fd)
|
||||||
proc.in = in;
|
dup2(new_fd, old_fd);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Proc createProcess(const char* const argv[], fd_t in, fd_t out, fd_t err)
|
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);
|
pipe(childIn);
|
||||||
|
p.in = childIn[1];
|
||||||
if(out == PIPE)
|
|
||||||
proc = _cppipe::createInOutRedirected(argv, childIn);
|
|
||||||
else
|
|
||||||
proc = _cppipe::createInRedirected(argv, childIn);
|
|
||||||
|
|
||||||
close(childIn[0]); // parent closes read side
|
|
||||||
}
|
}
|
||||||
else if(out == PIPE)
|
else
|
||||||
proc = _cppipe::createCapProcess(argv, in, err);
|
p.in = in;
|
||||||
else /* todo: err == PIPE */
|
|
||||||
proc = _cppipe::create(argv, in, out, err);
|
|
||||||
|
|
||||||
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[])
|
inline void exec_or_die(const char* const argv[])
|
||||||
{
|
{
|
||||||
execvp(argv[0], (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
|
_exit(1); // _exit since we are a child
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,6 +66,7 @@ private:
|
|||||||
bool execed_;
|
bool execed_;
|
||||||
|
|
||||||
friend Proc detach(const PendingCmd&);
|
friend Proc detach(const PendingCmd&);
|
||||||
|
friend Proc detachRedirIn(const PendingCmd&);
|
||||||
friend Proc detachRedirOut(const PendingCmd&);
|
friend Proc detachRedirOut(const PendingCmd&);
|
||||||
friend Proc detachRedirInOut(const PendingCmd&);
|
friend Proc detachRedirInOut(const PendingCmd&);
|
||||||
};
|
};
|
||||||
@@ -82,6 +83,9 @@ DeadProc run(const PendingCmd&);
|
|||||||
becomes: cmd.detach() */
|
becomes: cmd.detach() */
|
||||||
Proc detach(const PendingCmd&);
|
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 */
|
/* Detach but redirect output to a new pipe */
|
||||||
Proc detachRedirOut(const PendingCmd&);
|
Proc detachRedirOut(const PendingCmd&);
|
||||||
/* Also rediredct input */
|
/* 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);
|
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)
|
inline Proc detachRedirOut(const PendingCmd& ccmd)
|
||||||
{
|
{
|
||||||
auto& c = const_cast<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
|
// find the path of the cache for the given src_file path
|
||||||
fs::path get_cache_dir_path(const fs::path& src_file);
|
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);
|
MappedFile mapfile_for_writing(const fs::path& file);
|
||||||
|
|
||||||
// preprocess the src file, compare and overwrite the result to the previous version
|
// preprocess the src file, compare and overwrite the result to the previous version
|
||||||
// return the path of the preprocessed file if it's different
|
// return whether there was a difference
|
||||||
optional<fs::path> preprocess_and_compare();
|
bool preprocess_and_compare();
|
||||||
|
|
||||||
// only recompile if changes are present
|
// only recompile if changes are present
|
||||||
void compile_src_file();
|
void compile_src_file();
|
||||||
@@ -64,11 +64,12 @@ fs::path HOME;
|
|||||||
fs::path src_file;
|
fs::path src_file;
|
||||||
SrcType src_type;
|
SrcType src_type;
|
||||||
fs::path cache_dir;
|
fs::path cache_dir;
|
||||||
|
fs::path preprocessed_file;
|
||||||
fs::path bin; // cache bins to avoid recompiles
|
fs::path bin; // cache bins to avoid recompiles
|
||||||
|
|
||||||
// Options
|
// Options
|
||||||
bool debug = false;
|
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;
|
bool quick = false;
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -82,6 +83,10 @@ int main(int argc, char* argv[])
|
|||||||
src_file = find_path_to_src( argv[src_arg] );
|
src_file = find_path_to_src( argv[src_arg] );
|
||||||
src_type = find_src_type( argv[src_arg] );
|
src_type = find_src_type( argv[src_arg] );
|
||||||
cache_dir = get_cache_dir_path(src_file);
|
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();
|
bin = cache_dir / (debug ? DEBUG_PREFIX : "") += src_file.filename();
|
||||||
|
|
||||||
// Compile the src
|
// 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";
|
cerr << "File: " << src_file << " doesn't exist\n";
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
@@ -212,7 +217,7 @@ MappedFile mapfile_for_writing(const fs::path& file)
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
optional<fs::path> preprocess_and_compare()
|
bool preprocess_and_compare()
|
||||||
{
|
{
|
||||||
Cmd preprocess(
|
Cmd preprocess(
|
||||||
src_type == SrcType::C ? CC : CXX,
|
src_type == SrcType::C ? CC : CXX,
|
||||||
@@ -233,16 +238,33 @@ optional<fs::path> preprocess_and_compare()
|
|||||||
preprocess += "-xc++"; // treat the file as a .cpp
|
preprocess += "-xc++"; // treat the file as a .cpp
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read source from stdin
|
|
||||||
preprocess += "-";
|
|
||||||
|
|
||||||
|
|
||||||
if(!debug)
|
if(!debug)
|
||||||
preprocess += "-DNDEBUG";
|
preprocess += "-DNDEBUG";
|
||||||
|
|
||||||
// Preprocessed file from the previous run
|
// Read source from stdin
|
||||||
fs::path old_pp_path = cache_dir / (debug ? DEBUG_PREFIX : "") += src_file.stem()
|
preprocess += "-";
|
||||||
+= (src_type == SrcType::C ? ".i" : ".ii");
|
|
||||||
|
// 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);
|
Proc preprocessing = detachRedirInOut(preprocess);
|
||||||
|
|
||||||
@@ -264,36 +286,36 @@ optional<fs::path> preprocess_and_compare()
|
|||||||
if( !wait(preprocessing) ) // preprocessing failed
|
if( !wait(preprocessing) ) // preprocessing failed
|
||||||
exit(1);
|
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);
|
MappedFile old_pp = mapfile_for_writing(preprocessed_file);
|
||||||
if( !memcmp(old_pp.data, &new_pp[0], old_pp.len) ) // unchanged
|
if( !memcmp(old_pp.data, new_pp.data(), old_pp.len) ) // unchanged
|
||||||
{
|
{
|
||||||
return nullopt;
|
return false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
memcpy(old_pp.data, &new_pp[0], old_pp.len);
|
memcpy(old_pp.data, &new_pp[0], old_pp.len);
|
||||||
munmap(old_pp.data, old_pp.len);
|
munmap(old_pp.data, old_pp.len);
|
||||||
return old_pp_path;
|
return true;
|
||||||
}
|
}
|
||||||
// todo
|
// todo
|
||||||
// munmap(data, len);
|
// munmap(data, len);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ofstream pp_file(old_pp_path);
|
ofstream pp_file(preprocessed_file);
|
||||||
pp_file << new_pp;
|
pp_file << new_pp;
|
||||||
return old_pp_path;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ofstream pp_file(old_pp_path);
|
ofstream pp_file(preprocessed_file);
|
||||||
pp_file << new_pp;
|
pp_file << new_pp;
|
||||||
return old_pp_path;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -304,20 +326,19 @@ void compile_src_file()
|
|||||||
error_code ec;
|
error_code ec;
|
||||||
if(fs::last_write_time(src_file) < fs::last_write_time(bin, 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;
|
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
|
// Only compile if the source is newer then the bin
|
||||||
if(new_preprocessed || !fs::exists(bin))
|
if(file_changed || !fs::exists(bin))
|
||||||
{
|
{
|
||||||
|
|
||||||
Cmd compile(
|
Cmd compile(
|
||||||
src_type == SrcType::C ? CC : CXX,
|
src_type == SrcType::C ? CC : CXX,
|
||||||
new_preprocessed->c_str(),
|
preprocessed_file.c_str(),
|
||||||
"-o", bin.c_str()
|
"-o", bin.c_str()
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -335,9 +356,12 @@ void compile_src_file()
|
|||||||
|
|
||||||
|
|
||||||
if( !compile() ) // if failed to compile
|
if( !compile() ) // if failed to compile
|
||||||
|
{
|
||||||
|
fs::remove(bin);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void print_usage()
|
void print_usage()
|
||||||
{
|
{
|
||||||
|
|||||||
Regular → Executable
+1
@@ -1,3 +1,4 @@
|
|||||||
|
#!/usr/local/bin/cppipe
|
||||||
// Test cppipe functions
|
// Test cppipe functions
|
||||||
|
|
||||||
#include <cppipe/commands.hpp>
|
#include <cppipe/commands.hpp>
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
example #!/usr/bin/cppipe
|
||||||
description - advantages over manual compile
|
description - advantages over manual compile
|
||||||
man
|
man
|
||||||
tips (sigaction SIGCHILD, SIG_IGN, SIG_DFL)
|
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
|
make sure file descriptors are closed when no longer used
|
||||||
cppipe compile options from tft
|
cppipe compile options from tft
|
||||||
respect CXXFLAGS LDFLAGS
|
respect CXXFLAGS LDFLAGS
|
||||||
|
< PendingCmd store files we need to close
|
||||||
|
|
||||||
?
|
?
|
||||||
optional exec
|
optional exec
|
||||||
@@ -20,3 +22,4 @@ uninstall
|
|||||||
improve debug (the src file shown is the .ii)
|
improve debug (the src file shown is the .ii)
|
||||||
no optimizations option
|
no optimizations option
|
||||||
split
|
split
|
||||||
|
PendingCmd template
|
||||||
|
|||||||
Reference in New Issue
Block a user