Compare commits

...
10 Commits
Author SHA1 Message Date
vrd 59efef4b07 reallay the #! patch 2025-06-23 11:02:01 +03:00
vrd 7f3794e742 pass non-cppipe options to the compiler 2025-06-06 18:00:38 +03:00
vrd 370995978c todo.txt 2025-06-06 18:00:38 +03:00
vrd 9dc9f158fe temp solution for #! in include 2025-06-06 18:00:38 +03:00
vrd 03efe5c7c0 test improvement 2025-06-06 18:00:38 +03:00
vrd 0264245411 -n option 2025-06-06 18:00:38 +03:00
vrd e03dbf9e7a minor imprv 2025-06-06 18:00:38 +03:00
vrd a54f50a65a error check 2025-06-06 18:00:38 +03:00
vrd 8e172ba1cc use /var/cache when HOME is unset 2025-06-06 18:00:38 +03:00
vrd 0a5af1f757 Cmd implicit constructor 2025-06-06 18:00:38 +03:00
8 changed files with 101 additions and 46 deletions
+2 -1
View File
@@ -13,7 +13,8 @@ const char* CXX = "c++";
#define DEBUG_FLAGS "-g" #define DEBUG_FLAGS "-g"
// ...when not debugging // ...when not debugging
#define RELEASE_FLAGS "-Ofast", "-s" // -O2 seems to work best for both execution and compilation speed
#define RELEASE_FLAGS "-O2", "-s"
// ...for both C and C++ // ...for both C and C++
#define CPPFLAGS "-fwhole-program", "-march=native", "-Wall", "-Wextra", "-pipe" #define CPPFLAGS "-fwhole-program", "-march=native", "-Wall", "-Wextra", "-pipe"
+1 -2
View File
@@ -13,8 +13,7 @@ chmod 755 cppipe
mv cppipe ${PREFIX}/bin mv cppipe ${PREFIX}/bin
# Install headers # Install headers
mkdir -p ${PREFIX}/include/cppipe mkdir -p -m755 ${PREFIX}/include/cppipe
chmod 755 ${PREFIX}/include/cppipe
cp basicTypes.h commands.hpp commands.inl childProcess.hpp childProcess.inl ${PREFIX}/include/cppipe cp basicTypes.h commands.hpp commands.inl childProcess.hpp childProcess.inl ${PREFIX}/include/cppipe
chmod 644 ${PREFIX}/include/cppipe/* chmod 644 ${PREFIX}/include/cppipe/*
+4 -3
View File
@@ -2,10 +2,11 @@
set -e set -e
# Test cppipe functions # Test cppipe functions
OKs=$(test/functions_test.cppipe 2>/dev/null | grep OK | wc -l) OKs=$(test/functions_test.cppipe | grep OK | wc -l)
if ! [ $OKs = 13 ] EXPECTED=14
if ! [ $OKs = $EXPECTED ]
then then
echo "Functions test failed: EXPECTED 13 OKs, got $OKs" echo "Functions test failed: EXPECTED $EXPECTED OKs, got $OKs"
exit 1 exit 1
fi fi
echo Functions test OK! echo Functions test OK!
+10 -9
View File
@@ -18,11 +18,11 @@ class Cmd
public: public:
/* all args must be const char* */ /* all args must be const char* */
template<typename... Args> template<typename... Args>
explicit Cmd(Args... args) explicit Cmd(Args...);
: argv({args...})
{ /* Implicitly convert from { "command", "param" }
argv.push_back(nullptr); * e.g: exec({ "cmd", "arg" }); */
} Cmd(std::initializer_list<const char*> args);
/* Execute the command, if arguments are not given use stdin,out,err /* Execute the command, if arguments are not given use stdin,out,err
else use the given file desciptors. this can also be used else use the given file desciptors. this can also be used
@@ -45,8 +45,9 @@ public:
class PendingCmd class PendingCmd
{ {
public: public:
PendingCmd(std::initializer_list<const char*> cmd_args);
/* Can be implicitly created from a command */ /* Can be implicitly created from a command */
PendingCmd(const Cmd&, fd_t in=0, fd_t out=1, fd_t err=2); PendingCmd(Cmd, fd_t in=0, fd_t out=1, fd_t err=2);
/* Execute the command on destruction */ /* Execute the command on destruction */
~PendingCmd(); ~PendingCmd();
@@ -60,10 +61,10 @@ public:
/* Prevent a pending command from being executed on destruction */ /* Prevent a pending command from being executed on destruction */
void cancel(); void cancel();
const Cmd& cmd; Cmd cmd;
fd_t in, out, err; fd_t in=0, out=1, err=2;
private: private:
bool execed_; bool execed_ = false;
friend Proc detach(const PendingCmd&); friend Proc detach(const PendingCmd&);
friend Proc detachRedirIn(const PendingCmd&); friend Proc detachRedirIn(const PendingCmd&);
+20 -3
View File
@@ -28,6 +28,18 @@ namespace _cppipe
} }
} }
template<typename... Args>
inline Cmd::Cmd(Args... args)
: Cmd({ args... })
{
}
inline Cmd::Cmd(std::initializer_list<const char*> args)
: argv(args)
{
argv.push_back(nullptr);
}
inline DeadProc Cmd::operator()(fd_t in, fd_t out, fd_t err) const inline DeadProc Cmd::operator()(fd_t in, fd_t out, fd_t err) const
{ {
Proc p = createProcess(argv.data(), in, out, err); Proc p = createProcess(argv.data(), in, out, err);
@@ -58,13 +70,18 @@ inline Cmd& Cmd::operator+=(const char* arg)
return *this; return *this;
} }
inline PendingCmd::PendingCmd(std::initializer_list<const char*> cmd_args)
: cmd(cmd_args)
, in(0)
, out(1)
, err(2)
{}
inline PendingCmd::PendingCmd(const Cmd& origin, fd_t in, fd_t out, fd_t err) inline PendingCmd::PendingCmd(Cmd origin, fd_t in, fd_t out, fd_t err)
: cmd(origin) : cmd(std::move(origin))
, in(in) , in(in)
, out(out) , out(out)
, err(err) , err(err)
, execed_(false)
{} {}
inline PendingCmd::~PendingCmd() inline PendingCmd::~PendingCmd()
+46 -11
View File
@@ -60,7 +60,6 @@ SrcType find_src_type(string_view path);
const char DEBUG_PREFIX[] = "__DBG"; const char DEBUG_PREFIX[] = "__DBG";
// Context // Context
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;
@@ -71,6 +70,9 @@ fs::path bin; // cache bins to avoid recompiles
bool debug = false; bool debug = false;
// just compare timestamps of the source and bin, don't preprocess // just compare timestamps of the source and bin, don't preprocess
bool quick = false; bool quick = false;
// Just compile, don't run
bool dont_run = false;
vector<const char*> additional_compiler_args;
} }
@@ -79,7 +81,6 @@ int main(int argc, char* argv[])
int src_arg = parse_args_until_src(argc, argv); int src_arg = parse_args_until_src(argc, argv);
// Init context // Init context
HOME = getenv("HOME");
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);
@@ -93,6 +94,9 @@ int main(int argc, char* argv[])
compile_src_file(); compile_src_file();
// Run the src file without forking // Run the src file without forking
if(dont_run)
return 0;
Cmd run; Cmd run;
if(debug) // debug it with gdb if(debug) // debug it with gdb
{ {
@@ -103,6 +107,7 @@ int main(int argc, char* argv[])
run += bin.c_str(); run += bin.c_str();
for(int i = src_arg+1; i < argc; ++i) for(int i = src_arg+1; i < argc; ++i)
run += argv[i]; run += argv[i];
exec(run); exec(run);
} }
@@ -125,11 +130,16 @@ int parse_args_until_src(int argc, char* argv[])
{ {
print_usage(); print_usage();
cout << "Compile and run C/C++ source FILE\n" cout << "Compile and run C/C++ source FILE\n"
"Pass the ARGUMENTS to the compiled binary\n" "Pass the ARGUMENT to the compiled binary\n"
"The binaries are cached and recompiled only if the source or it's headers have changed\n\n" "The binaries are cached and recompiled only if the source or it's headers have changed\n\n"
"Options:\n" "Options:\n"
"-g debug the binary, asserts are also enabled\n" "-g debug the binary, asserts are also enabled\n"
"-q quicker, just compare source and binary time stamps, if included files were updated a recompile WON'T occur!\n\n" "-q quicker, just compare source and binary time stamps, if included files were updated a recompile WON'T occur!\n"
"-n don't run, just compile the file without running it\n\n"
"Any other argument that begins with '-' is passed to the compiler e.g.:\n"
" cppipe -O0 file.cpp\n\n"
"Environment variables:\n" "Environment variables:\n"
"CPPIPEPATH - ':'-separated list of directories to prepend to the FILE search path\n"; "CPPIPEPATH - ':'-separated list of directories to prepend to the FILE search path\n";
exit(0); exit(0);
@@ -142,6 +152,14 @@ int parse_args_until_src(int argc, char* argv[])
{ {
quick = true; quick = true;
} }
else if( arg == "-n" )
{
dont_run = true;
}
else if( !arg.empty() && arg[0] == '-') // if it's an unknown option pass it to the compiler
{
additional_compiler_args.push_back(argv[i]);
}
else // Then treat it as the src_arg else // Then treat it as the src_arg
{ {
src_arg = i; src_arg = i;
@@ -191,14 +209,19 @@ fs::path find_path_to_src(string_view src_file)
fs::path get_cache_dir_path(const fs::path& src_file) fs::path get_cache_dir_path(const fs::path& src_file)
{ {
fs::path cache_dir; fs::path cache_dir;
if(char* xdg_cache = getenv("XDG_CACHE_HOME")) if(char* XDG_CACHE = getenv("XDG_CACHE_HOME"))
{ {
cache_dir = xdg_cache; cache_dir = XDG_CACHE;
cache_dir /= "cppipe"; cache_dir /= "cppipe";
} }
else if(char* HOME = getenv("HOME"))
{
cache_dir = HOME;
cache_dir /= ".cache/cppipe";
}
else else
{ {
cache_dir = HOME / ".cache/cppipe"; cache_dir = "/var/cache/cppipe";
} }
cache_dir += fs::canonical( src_file ).parent_path(); cache_dir += fs::canonical( src_file ).parent_path();
fs::create_directories(cache_dir); fs::create_directories(cache_dir);
@@ -213,6 +236,12 @@ MappedFile mapfile_for_writing(const fs::path& file)
res.len = lseek(fd, 0, SEEK_END); res.len = lseek(fd, 0, SEEK_END);
res.data = (char*)mmap(nullptr, res.len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); res.data = (char*)mmap(nullptr, res.len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if(res.data == (void*)-1)
{
cerr << "ERROR: Couldn't map " << file << " for writing\n";
exit(1);
}
close(fd); close(fd);
return res; return res;
} }
@@ -283,8 +312,10 @@ bool preprocess_and_compare()
// Result of preprocessing as string // Result of preprocessing as string
string new_pp = read_to_end(preprocessing.out); string new_pp = read_to_end(preprocessing.out);
if( !wait(preprocessing) ) // preprocessing failed // TODO: decide what to do here, #! causes inevitavble non-fatal errors
exit(1); // maybe warn that preproccessing failed
// if( !wait(preprocessing) ) // preprocessing failed
// exit(1);
if( fs::exists(preprocessed_file) ) // todo: clean up if else blocks if( fs::exists(preprocessed_file) ) // todo: clean up if else blocks
{ {
@@ -349,11 +380,15 @@ void compile_src_file()
compile.append_args({ CXXFLAGS }); compile.append_args({ CXXFLAGS });
// Remap the debug source file since we compile from stdin
string debug_remap = "-fdebug-prefix-map=<stdin>=" + src_file.string();
if(debug) if(debug)
compile.append_args({ DEBUG_FLAGS }); compile.append_args({ DEBUG_FLAGS, debug_remap.c_str() });
else else
compile.append_args({ RELEASE_FLAGS }); compile.append_args({ RELEASE_FLAGS });
for(const char* arg: additional_compiler_args)
compile += arg;
if( !compile() ) // if failed to compile if( !compile() ) // if failed to compile
{ {
@@ -365,7 +400,7 @@ void compile_src_file()
void print_usage() void print_usage()
{ {
cout << "Usage: cppipe [OPTION]... FILE [ARGUMENTS]...\n"; cout << "Usage: cppipe [OPTION]... FILE [ARGUMENT]...\n";
} }
SrcType find_src_type(const string_view p) SrcType find_src_type(const string_view p)
+16 -16
View File
@@ -25,7 +25,7 @@ int main(int argc, char* argv[])
string out1 = $(ll + "src" | grep + "inl" | grep + "child"); string out1 = $(ll + "src" | grep + "inl" | grep + "child");
if(out1.find("childProcess.inl") != string::npos) if(out1.find("childProcess.inl") != string::npos)
cout << "OK 0/12" << endl; cout << "OK 0/13" << endl;
string out2 = $(echo + "abc" + "def"); string out2 = $(echo + "abc" + "def");
// "abc def" = 7 chars, trailing newlines are stripped by $() // "abc def" = 7 chars, trailing newlines are stripped by $()
@@ -35,8 +35,8 @@ int main(int argc, char* argv[])
exit(1); exit(1);
} }
Cmd success("echo", "OK 1/12"); Cmd success("echo", "OK 1/13");
Cmd fail("mkdir", "."); Cmd fail("false");
Cmd unexpected("echo", "FAILURE"); Cmd unexpected("echo", "FAILURE");
success && success &&
fail && fail &&
@@ -47,34 +47,34 @@ int main(int argc, char* argv[])
// unexpected && // unexpected &&
// unexpected; // unexpected;
Cmd write_file("echo", "Existing ", " ", "file. OK 2/12"); Cmd write_file("echo", "Existing ", " ", "file. OK 2/13");
write_file > "file.txt"; write_file > "file.txt";
grep + "Existing" < "file.txt"; grep + "Existing" < "file.txt";
echo + "Appended to file OK 3/12" >> "file.txt"; echo + "Appended to file OK 3/13" >> "file.txt";
grep + "Appended" < "file.txt" && grep + "Appended" < "file.txt" &&
rm + "file.txt" && rm + "file.txt" &&
fail || fail ||
Cmd("echo", "OK 4/12"); Cmd("echo", "OK 4/13");
echo + "OK 5/12" && echo + "OK 5/13" &&
echo + "OK 6/12", echo + "OK 6/13",
Cmd("echo", "OK 7/12"); Cmd("echo", "OK 7/13");
echo + "OK 8/12" & echo + "OK 8/13" &
echo + "OK 9/12" && echo + "OK 9/13" &&
echo + "OK 10/12"; echo + "OK 10/13";
// wait for all detached // wait for all detached
while(wait(nullptr) != -1); while(wait(nullptr) != -1);
Cmd run_OK = echo; Cmd run_OK = echo;
run_OK.append_args({ "OK 11/12" }); run_OK.append_args({ "OK 11/13" });
run( run_OK ); run( run_OK );
exec( echo + "OK 12/12" ); run({ "echo", "OK 12/13" });
// todo // The temporaty string is desroyed after the statement
// exec( echo + $(echo + "OK 11/12") ); exec( echo + $(echo + "OK 13/13").c_str() );
} }
+2 -1
View File
@@ -1,7 +1,8 @@
many points in name - rc.local.start
example #!/usr/bin/cppipe 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) condituonal main
- redirected processes block if their output is not read - redirected processes block if their output is not read
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