diff --git a/Makefile b/Makefile index 132318fe..8ed2f37b 100644 --- a/Makefile +++ b/Makefile @@ -123,7 +123,7 @@ endif endif ifneq ($(USE_CLANG),) -WARNING_FLAGS += -Wno-misleading-indentation -Wno-unknown-warning-option -Wno-c2x-extensions -Wno-unused-function -Wno-c++2b-extensions +WARNING_FLAGS += -Wno-misleading-indentation -Wno-unknown-warning-option -Wno-c2x-extensions -Wno-c++2b-extensions endif # this is the recommanded way to insert a , when calling functions diff --git a/README.md b/README.md index 70c90812..5ed71592 100644 --- a/README.md +++ b/README.md @@ -75,20 +75,20 @@ it has been tested with the dockers listed in the docker directory - the relative positions of these 4 dirs must remain the same, i.e. they must stay in the same directory with the same names. - specialization - you can specialize the build process to better suit your needs : - - this can be done by setting variables on the command line - - for example, you can run : make CC=/my/gcc - - PYTHON can be set to your preferred python. You will be told if it is not supported. + - this can be done by setting variables on the command line or in the environment + - for example, you can run : make CC=/my/gcc or CC=/my/gcc make + - PYTHON2 can be set to your preferred Python 2 (defaults to python2). You will be told if it is not supported. + - PYTHON can be set to your preferred Python 3 (defaults to python3). You will be told if it is not supported. - CC can be set to your preferred compiler. You will be told if it is not supported. - - LMAKE_OPT_LVL can be defined between 0 and 5 inclusive : - - -O compiler option is given the provided value, up to 3 - - if 0, the -g flag is also provided - - if 4 or above, -DNDEBUG is defined. There are *a lot* of assertions throughout the code, so it makes sens to run with -DNDEBUG. - furthermore, a few essential assertions are left active, even with -DNDEBUG - - if 5, no trace is generated + - LMAKE_OP can be defined as [0123][gG][dD][tT] (default is 3GDT) + - [0123] controls the -O option. + - [gG] controls the -g option : G passes it to enable debug, g does not. + - [dD] controls -DNDEBUG : D passes it to enable asserts, d does not. + - [tT] controls -DNO_TRACE : T does not pass it to enable traces, t passes it. - the -j flag of make is automatically set to the number of processors, you may want to override this, though - it is up to you to provide a suitable LD_LIBRARY_PATH value. - it will be transferred as a default value for rules, to the extent it is necessary to provide lmake semantic (mostly this means we keep what is necessary to run python) - - if you modify these variables, you should execute git clean as make will not detect this modification automatically + it will be transferred as a default value for rules, to the extent it is necessary to provide lmake semantic (mostly this means we keep what is necessary to run python). + - if you modify these variables, you should execute git clean as make will not detect such modifications automatically. # coding rules @@ -125,18 +125,17 @@ Names are suffixed with \_ if needed to suppress ambiguities - words include standard name such as syscall names or libc functions - special cases : - - - - - - - - - - - + + + + + + + + + +
abbrev full-name -
ddate disk date
dflag dependency flag
filename file name
lnk symbolic link
ongoing on going
pdate process date
regexpr regular expression
serdes serialize, deserialize
tflag target flag
wakeup wake_up
wrt with respect to
abbrev full-name +
ddate disk date
dflag dependency flag
filename file name
lnk symbolic link
ongoing on going
pdate process date
regexpr regular expression
serdes serialize, deserialize
tflag target flag
wrt with respect to
## layout diff --git a/TO_DO b/TO_DO index 065c5613..c018ec46 100644 --- a/TO_DO +++ b/TO_DO @@ -14,7 +14,6 @@ items : * missing some deps when reading elf - it seems that libc.so is missing at least in some occasions -* ld_audit does not seem to correctly bind symbols with ldopen on Ubuntu20 * reimplement hierarchical repositories - add a sub_repositories entry to config - map priorities to RuleIdx @@ -28,7 +27,6 @@ items : * LACK (not implemented but necessary for lmake semantic) **************************************************************************************************** -* rework side_targets versus side_deps * improve lshow -i - generate info on nodes * use Pdate (end of job) rather than Ddate (target date) to detect clash @@ -74,6 +72,10 @@ items : * ROBUSTNESS & MAINTENABILITY (fragile/difficult to read or maintain as long as not implemented) **************************************************************************************************** +* support 64-bits id + - configure with NBits rather than types + - in store/file.hh, reserve address space after NBits instead of type + - first candidate would be deps, by far the most demanding * add a warning when ids reach 15/16 of their limits * implement noexcept/except everywhere pertinent * use the Path struct instead of at/file diff --git a/_lib/lmake/rules.src.py b/_lib/lmake/rules.src.py index 21b93689..c52f5dcf 100644 --- a/_lib/lmake/rules.src.py +++ b/_lib/lmake/rules.src.py @@ -138,6 +138,10 @@ class _PyRule(Rule) : mask_python_deps = False def cmd() : # this will be executed before cmd() of concrete subclasses as cmd() are chained in case of inheritance if gen_module_deps or mask_python_deps : # fast path :if nothing to do, do nothing + try : import lmake + except ModuleNotFoundError : + import sys + sys.path[0:0] = (_lmake_dir+'/lib',) from lmake.import_machinery import fix_import fix_import(gen_module_deps=gen_module_deps,mask_python_deps=mask_python_deps) cmd.shell = '' # support shell cmd's that may launch python as a subprocess XXX : manage to execute fix_import() diff --git a/src/app.hh b/src/app.hh index 3defc35c..4d5cf957 100644 --- a/src/app.hh +++ b/src/app.hh @@ -15,8 +15,8 @@ extern ::string* g_lmake_dir ; // pointer to avoid init/fini order hazards, extern ::string* g_root_dir ; // pointer to avoid init/fini order hazards, absolute , root of repository extern ::string* g_exe_name ; // pointer to avoid init/fini order hazards, absolute , executable name for user messages -/**/ void app_init( Bool3 chk_version_=Yes , bool cd_root=true ) ; // if chk_version_==Maybe, it is ok to initialize stored version -static inline void app_init( bool cd_root ) { app_init(Yes,cd_root) ; } +/**/ void app_init( Bool3 chk_version_=Yes , bool cd_root=true ) ; // if chk_version_==Maybe, it is ok to initialize stored version +inline void app_init( bool cd_root ) { app_init(Yes,cd_root) ; } void chk_version( bool may_init=false , ::string const& admin_dir=AdminDir ) ; diff --git a/src/autodep/env.cc b/src/autodep/env.cc index fc0ec571..5ff409b3 100644 --- a/src/autodep/env.cc +++ b/src/autodep/env.cc @@ -10,11 +10,11 @@ using namespace Disk ; ::ostream& operator<<( ::ostream& os , AutodepEnv const& ade ) { os << "AutodepEnv(" ; if (ade.active) { - /**/ os << static_cast(ade) ; - /**/ os <<','<< ade.service ; - if ( ade.auto_mkdir ) os <<",auto_mkdir" ; - if ( ade.ignore_stat) os <<",ignore_stat" ; - if (!ade.disabled ) os <<",disabled" ; + /**/ os << static_cast(ade) ; + /**/ os <<','<< ade.service ; + if (ade.auto_mkdir ) os <<",auto_mkdir" ; + if (ade.ignore_stat) os <<",ignore_stat" ; + if (ade.disabled ) os <<",disabled" ; } return os <<')' ; } diff --git a/src/autodep/gather.cc b/src/autodep/gather.cc index 1113c3fc..9dbf1310 100644 --- a/src/autodep/gather.cc +++ b/src/autodep/gather.cc @@ -476,6 +476,5 @@ void Gather::reorder(bool at_end) { i_dst++ ; } accesses.resize(i_dst) ; - if (at_end) access_map.clear() ; // safer not to leave outdated info - else for( NodeIdx i=0 ; i static inline uintptr_t _la_symbind( Sym* sym , unsigned int /*ndx*/ , uintptr_t* /*ref_cook*/ , uintptr_t* def_cook , unsigned int* /*flags*/ , const char* sym_name ) { +template uintptr_t _la_symbind( Sym* sym , unsigned int /*ndx*/ , uintptr_t* /*ref_cook*/ , uintptr_t* def_cook , unsigned int* /*flags*/ , const char* sym_name ) { // auditer() ; // force Audit static init if (g_force_orig) goto Ignore ; // avoid recursion loop diff --git a/src/autodep/ld_preload.cc b/src/autodep/ld_preload.cc index 3d95edb0..51c60685 100644 --- a/src/autodep/ld_preload.cc +++ b/src/autodep/ld_preload.cc @@ -3,6 +3,6 @@ // This program is free software: you can redistribute/modify under the terms of the GPL-v3 (https://www.gnu.org/licenses/gpl-3.0.html). // This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -static inline bool started() { return true ; } +static bool started() { return true ; } #include "ld.x.cc" diff --git a/src/autodep/ld_preload_jemalloc.cc b/src/autodep/ld_preload_jemalloc.cc index a168ecd5..00e8a760 100644 --- a/src/autodep/ld_preload_jemalloc.cc +++ b/src/autodep/ld_preload_jemalloc.cc @@ -8,7 +8,7 @@ // ensure malloc has been initialized (at least at first call to malloc) in case jemalloc is used with ld_preload to avoid malloc_init->open->malloc->malloc_init loop static bool _g_started = false ; -static inline bool started() { return _g_started ; } +static bool started() { return _g_started ; } #define LD_PRELOAD_JEMALLOC #include "ld.x.cc" diff --git a/src/autodep/ld_server.cc b/src/autodep/ld_server.cc index 61236eb7..79b18757 100644 --- a/src/autodep/ld_server.cc +++ b/src/autodep/ld_server.cc @@ -8,7 +8,7 @@ thread_local bool AutodepLock::t_active = false ; /**/ ::mutex AutodepLock::_s_mutex ; -static inline bool started() { return AutodepLock::t_active ; } // no auto-start for server +static bool started() { return AutodepLock::t_active ; } // no auto-start for server #define IN_SERVER #include "ld.x.cc" diff --git a/src/autodep/record.cc b/src/autodep/record.cc index adf59acc..73854f3f 100644 --- a/src/autodep/record.cc +++ b/src/autodep/record.cc @@ -173,9 +173,9 @@ Record::Mkdir::Mkdir( Record& r , Path&& path , ::string&& c ) : Solve{r,::move( if (file_loc==FileLoc::Repo) r._report_guard( ::move(real) , ::move(c) ) ; } -static inline bool _do_stat (int flags) { return flags&O_PATH ; } -static inline bool _do_read (int flags) { return !_do_stat(flags) && (flags&O_ACCMODE)!=O_WRONLY && !(flags&O_TRUNC) ; } -static inline bool _do_write(int flags) { return !_do_stat(flags) && (flags&O_ACCMODE)!=O_RDONLY ; } +static bool _do_stat (int flags) { return flags&O_PATH ; } +static bool _do_read (int flags) { return !_do_stat(flags) && (flags&O_ACCMODE)!=O_WRONLY && !(flags&O_TRUNC) ; } +static bool _do_write(int flags) { return !_do_stat(flags) && (flags&O_ACCMODE)!=O_RDONLY ; } Record::Open::Open( Record& r , Path&& path , int flags , ::string&& c ) : Solve{ r , ::move(path) , bool(flags&O_NOFOLLOW) , _do_read(flags) , true/*allow_tmp_map*/ , to_string(c,::hex,'.',flags) } , do_write{_do_write(flags)} diff --git a/src/autodep/syscall_tab.cc b/src/autodep/syscall_tab.cc index 8e1eb9e6..808774ca 100644 --- a/src/autodep/syscall_tab.cc +++ b/src/autodep/syscall_tab.cc @@ -58,7 +58,7 @@ template static Record::Path _path( pid_t pid , uint64_t const* args ) // updating args is meaningful only when processing calls to the syscall function with ld_audit & ld_preload // when autodep is ptrace, tmp mapping is not supported and such args updating is ignored as args have been copied from tracee and are not copied back to it -template static inline void _update( uint64_t* args , Record::Path const& p ) { +template void _update( uint64_t* args , Record::Path const& p ) { SWEAR(p.has_at==At) ; if (At) args[0 ] = p.at ; /**/ args[At] = reinterpret_cast(p.file) ; @@ -66,7 +66,7 @@ template static inline void _update( uint64_t* args , Record::Path cons static constexpr int FlagAlways = -1 ; static constexpr int FlagNever = -2 ; -template static inline bool _flag( uint64_t args[6] , int flag ) { +template bool _flag( uint64_t args[6] , int flag ) { switch (FlagArg) { case FlagAlways : return true ; case FlagNever : return false ; @@ -75,13 +75,13 @@ template static inline bool _flag( uint64_t args[6] , int flag ) { } // chdir -template static inline void _entry_chdir( void* & ctx , Record& r , pid_t pid , uint64_t args[6] , const char* comment ) { +template void _entry_chdir( void* & ctx , Record& r , pid_t pid , uint64_t args[6] , const char* comment ) { try { if (At) { Record::Chdir* cd = new Record::Chdir( r , {Fd(args[0]) } , comment ) ; ctx = cd ; } else { Record::Chdir* cd = new Record::Chdir( r , {_path(pid,args+0)} , comment ) ; ctx = cd ; _update(args+0,*cd) ; } } catch (int) {} } -static inline int64_t/*res*/ _exit_chdir( void* ctx , Record& r , pid_t pid , int64_t res ) { +static int64_t/*res*/ _exit_chdir( void* ctx , Record& r , pid_t pid , int64_t res ) { if (!ctx) return res ; Record::Chdir* cd = static_cast(ctx) ; (*cd)(r,res,pid) ; @@ -90,14 +90,14 @@ static inline int64_t/*res*/ _exit_chdir( void* ctx , Record& r , pid_t pid , in } // chmod -template void static inline _entry_chmod( void* & ctx , Record& r , pid_t pid , uint64_t args[6] , const char* comment ) { +template void _entry_chmod( void* & ctx , Record& r , pid_t pid , uint64_t args[6] , const char* comment ) { try { Record::Chmod* cm = new Record::Chmod( r , _path(pid,args+0) , args[1+At]&S_IXUSR , _flag(args,AT_SYMLINK_NOFOLLOW) , comment ) ; ctx = cm ; _update(args+0,*cm) ; } catch (int) {} } -static inline int64_t/*res*/ _exit_chmod( void* ctx , Record& r , pid_t , int64_t res ) { +static int64_t/*res*/ _exit_chmod( void* ctx , Record& r , pid_t , int64_t res ) { if (!ctx) return res ; Record::Chmod* cm = static_cast(ctx) ; (*cm)(r,res) ; @@ -106,7 +106,7 @@ static inline int64_t/*res*/ _exit_chmod( void* ctx , Record& r , pid_t , int64_ } // creat -static inline void _entry_creat( void* & ctx , Record& r , pid_t pid , uint64_t args[6] , const char* comment ) { +static void _entry_creat( void* & ctx , Record& r , pid_t pid , uint64_t args[6] , const char* comment ) { try { Record::Open* o = new Record::Open( r , _path(pid,args+0) , O_WRONLY|O_CREAT|O_TRUNC , comment ) ; ctx = o ; @@ -118,7 +118,7 @@ static inline void _entry_creat( void* & ctx , Record& r , pid_t pid , uint64_t // execve // must be called before actual syscall execution as after execution, info is no more available -template static inline void _entry_execve( void* & /*ctx*/ , Record& r , pid_t pid , uint64_t args[6] , const char* comment ) { +template static void _entry_execve( void* & /*ctx*/ , Record& r , pid_t pid , uint64_t args[6] , const char* comment ) { try { Record::Exec e{ r , _path(pid,args+0) , _flag(args,AT_SYMLINK_NOFOLLOW) , comment } ; _update(args+0,e) ; @@ -127,11 +127,11 @@ template static inline void _entry_execve( void* & /*ctx*/ // getcwd // getcwd is only necessary if tmp is mapped (not in table with ptrace) -static inline void _entry_getcwd( void* & ctx , Record& , pid_t , uint64_t args[6] , const char* /*comment*/ ) { +static void _entry_getcwd( void* & ctx , Record& , pid_t , uint64_t args[6] , const char* /*comment*/ ) { size_t* sz = new size_t{args[1]} ; ctx = sz ; } -static inline int64_t/*res*/ _exit_getcwd( void* ctx , Record& , pid_t pid , int64_t res ) { +static int64_t/*res*/ _exit_getcwd( void* ctx , Record& , pid_t pid , int64_t res ) { if (!res ) return res ; // in case of error, man getcwd says buffer is undefined => nothing to do if (!Record::s_has_tmp_view()) return res ; // no tmp mapping => nothing to do SWEAR(pid==0,pid) ; // tmp mapping is not supported with ptrace (need to report fixed result to caller) @@ -143,7 +143,7 @@ static inline int64_t/*res*/ _exit_getcwd( void* ctx , Record& , pid_t pid , int } // hard link -template static inline void _entry_lnk( void* & ctx , Record& r , pid_t pid , uint64_t args[6] , const char* comment ) { +template void _entry_lnk( void* & ctx , Record& r , pid_t pid , uint64_t args[6] , const char* comment ) { try { Record::Lnk* l = new Record::Lnk( r , _path(pid,args+0) , _path(pid,args+1+At) , _flag(args,AT_SYMLINK_NOFOLLOW) , comment ) ; ctx = l ; @@ -151,7 +151,7 @@ template static inline void _entry_lnk( void* & ctx , Recor _update(args+2,l->dst) ; } catch (int) {} } -static inline int64_t/*res*/ _exit_lnk( void* ctx , Record& r , pid_t /*pid */, int64_t res ) { +static int64_t/*res*/ _exit_lnk( void* ctx , Record& r , pid_t /*pid */, int64_t res ) { if (!ctx) return res ; Record::Lnk* l = static_cast(ctx) ; (*l)(r,res) ; @@ -160,7 +160,7 @@ static inline int64_t/*res*/ _exit_lnk( void* ctx , Record& r , pid_t /*pid */, } // mkdir -template static inline void _entry_mkdir( void* & /*ctx*/ , Record& r , pid_t pid , uint64_t args[6] , const char* comment ) { +template void _entry_mkdir( void* & /*ctx*/ , Record& r , pid_t pid , uint64_t args[6] , const char* comment ) { try { Record::Mkdir m{ r , _path(pid,args+0) , comment } ; _update(args+0,m) ; @@ -168,7 +168,7 @@ template static inline void _entry_mkdir( void* & /*ctx*/ , Record& r , } // open -template static inline void _entry_open( void* & ctx , Record& r , pid_t pid , uint64_t args[6] , const char* comment ) { +template void _entry_open( void* & ctx , Record& r , pid_t pid , uint64_t args[6] , const char* comment ) { try { Record::Open* o = new Record::Open( r , _path(pid,args+0) , args[1+At]/*flags*/ , comment ) ; ctx = o ; @@ -176,7 +176,7 @@ template static inline void _entry_open( void* & ctx , Record& r , pid_ } catch (int) {} } -static inline int64_t/*res*/ _exit_open( void* ctx , Record& r , pid_t /*pid*/ , int64_t res ) { +static int64_t/*res*/ _exit_open( void* ctx , Record& r , pid_t /*pid*/ , int64_t res ) { if (!ctx) return res ; Record::Open* o = static_cast(ctx) ; (*o)( r , res ) ; @@ -185,14 +185,14 @@ static inline int64_t/*res*/ _exit_open( void* ctx , Record& r , pid_t /*pid*/ , } // read_lnk -template static inline void _entry_read_lnk( void* & ctx , Record& r , pid_t pid , uint64_t args[6] , const char* comment ) { +template void _entry_read_lnk( void* & ctx , Record& r , pid_t pid , uint64_t args[6] , const char* comment ) { try { Record::Readlnk* rl = new Record::Readlnk( r , _path(pid,args+0) , comment ) ; ctx = rl ; _update(args+0,*rl) ; } catch (int) {} } -static inline int64_t/*res*/ _exit_read_lnk( void* ctx , Record& r , pid_t pid , int64_t res ) { +static int64_t/*res*/ _exit_read_lnk( void* ctx , Record& r , pid_t pid , int64_t res ) { if (!ctx) return res ; Record::Readlnk* rl = static_cast(ctx) ; SWEAR( pid==0 || !Record::s_has_tmp_view() , pid ) ; // tmp mapping is not supported with ptrace (need to report new value to caller) @@ -202,7 +202,7 @@ static inline int64_t/*res*/ _exit_read_lnk( void* ctx , Record& r , pid_t pid , } // rename -template static inline void _entry_rename( void* & ctx , Record& r , pid_t pid , uint64_t args[6] , const char* comment ) { +template void _entry_rename( void* & ctx , Record& r , pid_t pid , uint64_t args[6] , const char* comment ) { try { #ifdef RENAME_EXCHANGE bool exchange = _flag(args,RENAME_EXCHANGE) ; @@ -220,7 +220,7 @@ template static inline void _entry_rename( void* & ctx , Re _update(args+2,rn->dst) ; } catch (int) {} } -static inline int64_t/*res*/ _exit_rename( void* ctx , Record& r , pid_t /*pid*/ , int64_t res ) { +static int64_t/*res*/ _exit_rename( void* ctx , Record& r , pid_t /*pid*/ , int64_t res ) { if (!ctx) return res ; Record::Rename* rn = static_cast(ctx) ; (*rn)(r,res) ; @@ -229,14 +229,14 @@ static inline int64_t/*res*/ _exit_rename( void* ctx , Record& r , pid_t /*pid*/ } // symlink -template static inline void _entry_sym_lnk( void* & ctx , Record& r , pid_t pid , uint64_t args[6] , const char* comment ) { +template void _entry_sym_lnk( void* & ctx , Record& r , pid_t pid , uint64_t args[6] , const char* comment ) { try { Record::Symlnk* sl = new Record::Symlnk( r , _path(pid,args+1) , comment ) ; ctx = sl ; _update(args+1,*sl) ; } catch (int) {} } -static inline int64_t/*res*/ _exit_sym_lnk( void* ctx , Record& r , pid_t , int64_t res ) { +static int64_t/*res*/ _exit_sym_lnk( void* ctx , Record& r , pid_t , int64_t res ) { if (!ctx) return res ; Record::Symlnk* sl = static_cast(ctx) ; (*sl)(r,res) ; @@ -245,7 +245,7 @@ static inline int64_t/*res*/ _exit_sym_lnk( void* ctx , Record& r , pid_t , int6 } // unlink -template static inline void _entry_unlnk( void* & ctx , Record& r , pid_t pid , uint64_t args[6] , const char* comment ) { +template void _entry_unlnk( void* & ctx , Record& r , pid_t pid , uint64_t args[6] , const char* comment ) { try { bool rmdir = _flag(args,AT_REMOVEDIR) ; Record::Unlnk* u = new Record::Unlnk( r , _path(pid,args+0) , rmdir , comment ) ; @@ -253,7 +253,7 @@ template static inline void _entry_unlnk( void* & ctx , Rec _update(args+0,*u) ; } catch (int) {} } -static inline int64_t/*res*/ _exit_unlnk( void* ctx , Record& r , pid_t , int64_t res ) { +static int64_t/*res*/ _exit_unlnk( void* ctx , Record& r , pid_t , int64_t res ) { if (!ctx) return res ; Record::Unlnk* u = static_cast(ctx) ; (*u)(r,res) ; @@ -262,7 +262,7 @@ static inline int64_t/*res*/ _exit_unlnk( void* ctx , Record& r , pid_t , int64_ } // access -template static inline void _entry_stat( void* & /*ctx*/ , Record& r , pid_t pid , uint64_t args[6] , const char* comment ) { +template void _entry_stat( void* & /*ctx*/ , Record& r , pid_t pid , uint64_t args[6] , const char* comment ) { try { Record::Stat s{ r , _path(pid,args+0) , _flag(args,AT_SYMLINK_NOFOLLOW) , comment } ; _update(args+0,s) ; diff --git a/src/client.hh b/src/client.hh index ebc3d131..9deaaaf6 100644 --- a/src/client.hh +++ b/src/client.hh @@ -24,7 +24,7 @@ struct AutoCloseFdPair { extern AutoCloseFdPair g_server_fds ; -static inline Rc mk_rc(Bool3 ok) { +inline Rc mk_rc(Bool3 ok) { switch (ok) { case Yes : return Rc::Ok ; case Maybe : return Rc::Format ; diff --git a/src/disk.cc b/src/disk.cc index 60d3e09b..0de8e8fb 100644 --- a/src/disk.cc +++ b/src/disk.cc @@ -179,7 +179,7 @@ namespace Disk { return res ; } - static inline int/*n_dirs*/ _mkdir( Fd at , ::string const& dir , NfsGuard* nfs_guard , bool multi , bool unlnk_ok ) { + static int/*n_dirs*/ _mkdir( Fd at , ::string const& dir , NfsGuard* nfs_guard , bool multi , bool unlnk_ok ) { ::vector_s to_mk { dir } ; const char* msg = nullptr ; int res = 0 ; @@ -385,7 +385,7 @@ namespace Disk { // - avoid ::string copying as much as possible // - do not support links outside repo & tmp, except from /proc (which is meaningful) // - note that besides syscalls, this algo is very fast and caching intermediate results could degrade performances (checking the cache could take as long as doing the job) - static inline int _get_symloop_max() { // max number of links to follow before decreting it is a loop + static int _get_symloop_max() { // max number of links to follow before decreting it is a loop int res = ::sysconf(_SC_SYMLOOP_MAX) ; if (res>=0) return res ; else return _POSIX_SYMLOOP_MAX ; @@ -533,10 +533,10 @@ namespace Disk { ::string interpreter ; interpreter.reserve(256) ; ::string root_dir_s = _env->root_dir+'/' ; // from tmp, we can go back to repo - for( int i=0 ; i<=4 ; i++ ) { // interpret #! recursively (4 levels as per man execve) + for( int i=0 ; i<=4 ; i++ ) { // interpret #! recursively (4 levels as per man execve) for( ::string& l : sr.lnks ) res.emplace_back(::move(l),Accesses(Access::Lnk)) ; // - if (sr.file_loc>FileLoc::Dep && sr.file_loc!=FileLoc::Tmp) break ; // if we escaped from the repo, there is no more deps to gather + if (sr.file_loc>FileLoc::Dep && sr.file_loc!=FileLoc::Tmp) break ; // if we escaped from the repo, there is no more deps to gather // if (sr.mapped) throw to_string("executing ",mk_file(sr.real)," with mapped files along its interpreter path from ",_tmp_view," to ",_env->tmp_dir," would require to modify file contents") ; @@ -549,11 +549,11 @@ namespace Disk { if (!real_stream.read(hdr,sizeof(hdr))) break ; if (strncmp(hdr,"#!",2)!=0 ) break ; interpreter.resize(256) ; - real_stream.getline(interpreter.data(),interpreter.size()) ; // man execve specifies that data beyond 255 chars are ignored + real_stream.getline(interpreter.data(),interpreter.size()) ; // man execve specifies that data beyond 255 chars are ignored if (!real_stream.gcount()) break ; interpreter.resize(real_stream.gcount()) ; - if ( size_t pos = interpreter.find(' ' ) ; pos!=Npos ) interpreter.resize(pos) ; // interpreter is the first word - else if ( size_t pos = interpreter.find('\0') ; pos!=Npos ) interpreter.resize(pos) ; // interpreter is the entire line (or the first \0 delimited word) + if ( size_t pos = interpreter.find(' ' ) ; pos!=Npos ) interpreter.resize(pos) ; // interpreter is the first word + else if ( size_t pos = interpreter.find('\0') ; pos!=Npos ) interpreter.resize(pos) ; // interpreter is the entire line (or the first \0 delimited word) // recurse sr = solve(interpreter,false/*no_follow*/) ; } diff --git a/src/disk.hh b/src/disk.hh index f0c07df5..c0ba8658 100644 --- a/src/disk.hh +++ b/src/disk.hh @@ -150,55 +150,55 @@ namespace Disk { bool/*done*/ uniquify ( Fd at , ::string const& file ) ; void rmdir ( Fd at , ::string const& dir ) ; // - static inline void lnk( Fd at , ::string const& file , ::string const& target ) { + inline void lnk( Fd at , ::string const& file , ::string const& target ) { if (::symlinkat(target.c_str(),at,file.c_str())!=0) { ::string at_str = at==Fd::Cwd ? ""s : to_string('<',int(at),">/") ; throw to_string("cannot create symlink from ",at_str,file," to ",target) ; } } - static inline Fd open_read( Fd at , ::string const& filename ) { + inline Fd open_read( Fd at , ::string const& filename ) { return ::openat( at , filename.c_str() , O_RDONLY|O_CLOEXEC , 0666 ) ; } - static inline Fd open_write( Fd at , ::string const& filename , bool append=false , bool exe=false , bool read_only=false ) { + inline Fd open_write( Fd at , ::string const& filename , bool append=false , bool exe=false , bool read_only=false ) { dir_guard(at,filename) ; return ::openat( at , filename.c_str() , O_WRONLY|O_CREAT|O_NOFOLLOW|O_CLOEXEC|(append?O_APPEND:O_TRUNC) , 0777 & ~(exe?0000:0111) & ~(read_only?0222:0000) ) ; } - static inline ::string read_lnk( Fd at , ::string const& file ) { + inline ::string read_lnk( Fd at , ::string const& file ) { char buf[PATH_MAX] ; ssize_t cnt = ::readlinkat(at,file.c_str(),buf,PATH_MAX) ; if ( cnt<0 || cnt>=PATH_MAX ) return {} ; return {buf,size_t(cnt)} ; } - static inline bool is_reg ( Fd at , ::string const& file={} , bool no_follow=true ) { return FileInfo(at,file,no_follow).is_reg() ; } - static inline bool is_dir ( Fd at , ::string const& file={} , bool no_follow=true ) { return FileInfo(at,file,no_follow).tag()==FileTag::Dir ; } - static inline bool is_target( Fd at , ::string const& file={} , bool no_follow=true ) { return +FileInfo(at,file,no_follow) ; } - static inline bool is_exe ( Fd at , ::string const& file={} , bool no_follow=true ) { return FileInfo(at,file,no_follow).tag()==FileTag::Exe ; } - static inline Ddate file_date( Fd at , ::string const& file={} , bool no_follow=true ) { return FileInfo(at,file,no_follow).date ; } + inline bool is_reg ( Fd at , ::string const& file={} , bool no_follow=true ) { return FileInfo(at,file,no_follow).is_reg() ; } + inline bool is_dir ( Fd at , ::string const& file={} , bool no_follow=true ) { return FileInfo(at,file,no_follow).tag()==FileTag::Dir ; } + inline bool is_target( Fd at , ::string const& file={} , bool no_follow=true ) { return +FileInfo(at,file,no_follow) ; } + inline bool is_exe ( Fd at , ::string const& file={} , bool no_follow=true ) { return FileInfo(at,file,no_follow).tag()==FileTag::Exe ; } + inline Ddate file_date( Fd at , ::string const& file={} , bool no_follow=true ) { return FileInfo(at,file,no_follow).date ; } - static inline ::vector_s lst_dir ( ::string const& dir , ::string const& prefix={} ) { return lst_dir (Fd::Cwd,dir ,prefix ) ; } - static inline ::vector_s walk ( ::string const& file , ::string const& prefix={} ) { return walk (Fd::Cwd,file,prefix ) ; } - static inline int/*n_dirs*/ mkdir ( ::string const& dir , bool multi=true , bool unlnk_ok=false ) { return mkdir (Fd::Cwd,dir , multi,unlnk_ok ) ; } - static inline int/*n_dirs*/ mkdir ( ::string const& dir , NfsGuard& ng , bool multi=true , bool unlnk_ok=false ) { return mkdir (Fd::Cwd,dir ,ng,multi,unlnk_ok ) ; } - static inline ::string const& dir_guard ( ::string const& file ) { dir_guard (Fd::Cwd,file) ; return file ; } - static inline void unlnk_inside( ::string const& dir ) { unlnk_inside(Fd::Cwd,dir ) ; } - static inline bool/*done*/ unlnk ( ::string const& file , bool dir_ok=false ) { return unlnk (Fd::Cwd,file,dir_ok ) ; } - static inline bool/*done*/ uniquify ( ::string const& file ) { return uniquify (Fd::Cwd,file ) ; } - static inline void rmdir ( ::string const& file ) { rmdir (Fd::Cwd,file ) ; } - static inline void lnk ( ::string const& file , ::string const& target ) { lnk (Fd::Cwd,file,target ) ; } - static inline Fd open_read ( ::string const& file ) { return open_read (Fd::Cwd,file ) ; } - static inline Fd open_write ( ::string const& file , bool append=false , bool exe=false , bool read_only=false ) { return open_write (Fd::Cwd,file,append,exe,read_only) ; } - static inline ::string read_lnk ( ::string const& file ) { return read_lnk (Fd::Cwd,file ) ; } - static inline bool is_reg ( ::string const& file , bool no_follow=true ) { return is_reg (Fd::Cwd,file,no_follow ) ; } - static inline bool is_dir ( ::string const& file , bool no_follow=true ) { return is_dir (Fd::Cwd,file,no_follow ) ; } - static inline bool is_target ( ::string const& file , bool no_follow=true ) { return is_target (Fd::Cwd,file,no_follow ) ; } - static inline bool is_exe ( ::string const& file , bool no_follow=true ) { return is_exe (Fd::Cwd,file,no_follow ) ; } - static inline Ddate file_date ( ::string const& file , bool no_follow=true ) { return file_date (Fd::Cwd,file,no_follow ) ; } + inline ::vector_s lst_dir ( ::string const& dir , ::string const& prefix={} ) { return lst_dir (Fd::Cwd,dir ,prefix ) ; } + inline ::vector_s walk ( ::string const& file , ::string const& prefix={} ) { return walk (Fd::Cwd,file,prefix ) ; } + inline int/*n_dirs*/ mkdir ( ::string const& dir , bool multi=true , bool unlnk_ok=false ) { return mkdir (Fd::Cwd,dir , multi,unlnk_ok ) ; } + inline int/*n_dirs*/ mkdir ( ::string const& dir , NfsGuard& ng , bool multi=true , bool unlnk_ok=false ) { return mkdir (Fd::Cwd,dir ,ng,multi,unlnk_ok ) ; } + inline ::string const& dir_guard ( ::string const& file ) { dir_guard (Fd::Cwd,file) ; return file ; } + inline void unlnk_inside( ::string const& dir ) { unlnk_inside(Fd::Cwd,dir ) ; } + inline bool/*done*/ unlnk ( ::string const& file , bool dir_ok=false ) { return unlnk (Fd::Cwd,file,dir_ok ) ; } + inline bool/*done*/ uniquify ( ::string const& file ) { return uniquify (Fd::Cwd,file ) ; } + inline void rmdir ( ::string const& file ) { rmdir (Fd::Cwd,file ) ; } + inline void lnk ( ::string const& file , ::string const& target ) { lnk (Fd::Cwd,file,target ) ; } + inline Fd open_read ( ::string const& file ) { return open_read (Fd::Cwd,file ) ; } + inline Fd open_write ( ::string const& file , bool append=false , bool exe=false , bool read_only=false ) { return open_write (Fd::Cwd,file,append,exe,read_only) ; } + inline ::string read_lnk ( ::string const& file ) { return read_lnk (Fd::Cwd,file ) ; } + inline bool is_reg ( ::string const& file , bool no_follow=true ) { return is_reg (Fd::Cwd,file,no_follow ) ; } + inline bool is_dir ( ::string const& file , bool no_follow=true ) { return is_dir (Fd::Cwd,file,no_follow ) ; } + inline bool is_target ( ::string const& file , bool no_follow=true ) { return is_target (Fd::Cwd,file,no_follow ) ; } + inline bool is_exe ( ::string const& file , bool no_follow=true ) { return is_exe (Fd::Cwd,file,no_follow ) ; } + inline Ddate file_date ( ::string const& file , bool no_follow=true ) { return file_date (Fd::Cwd,file,no_follow ) ; } - static inline ::string cwd() { + inline ::string cwd() { char buf[PATH_MAX] ; // use posix, not linux extension that allows to pass nullptr as argument and malloc's the returned string char* cwd = ::getcwd(buf,PATH_MAX) ; if (!cwd) throw "cannot get cwd"s ; @@ -208,19 +208,19 @@ namespace Disk { else return res ; } - static inline bool is_abs (::string const& name ) { return !name || name [0]=='/' ; } // name is (/)* or (/)* with =[^/]+, empty name is necessarily absolute - static inline bool is_abs_s(::string const& name_s) { return name_s[0]=='/' ; } // name_s is (/)* or /(/)* with =[^/]+, empty name_s is necessarily relative + inline bool is_abs (::string const& name ) { return !name || name [0]=='/' ; } // name is (/)* or (/)* with =[^/]+, empty name is necessarily absolute + inline bool is_abs_s(::string const& name_s) { return name_s[0]=='/' ; } // name_s is (/)* or /(/)* with =[^/]+, empty name_s is necessarily relative // - static inline bool is_lcl (::string const& name ) { return !( is_abs (name ) || name .starts_with("../") || name==".." ) ; } - static inline bool is_lcl_s(::string const& name_s) { return !( is_abs_s(name_s) || name_s.starts_with("../") ) ; } + inline bool is_lcl (::string const& name ) { return !( is_abs (name ) || name .starts_with("../") || name==".." ) ; } + inline bool is_lcl_s(::string const& name_s) { return !( is_abs_s(name_s) || name_s.starts_with("../") ) ; } // - /**/ ::string mk_lcl( ::string const& file , ::string const& dir_s ) ; // return file (passed as from dir_s origin) as seen from dir_s - /**/ ::string mk_glb( ::string const& file , ::string const& dir_s ) ; // return file (passed as from dir_s ) as seen from dir_s origin - static inline ::string mk_abs( ::string const& file , ::string const& dir_s ) { // return file (passed as from dir_s ) as absolute + /**/ ::string mk_lcl( ::string const& file , ::string const& dir_s ) ; // return file (passed as from dir_s origin) as seen from dir_s + /**/ ::string mk_glb( ::string const& file , ::string const& dir_s ) ; // return file (passed as from dir_s ) as seen from dir_s origin + inline ::string mk_abs( ::string const& file , ::string const& dir_s ) { // return file (passed as from dir_s ) as absolute SWEAR( is_abs_s(dir_s) , dir_s ) ; return mk_glb(file,dir_s) ; } - static inline ::string mk_rel( ::string const& file , ::string const& dir_s ) { + inline ::string mk_rel( ::string const& file , ::string const& dir_s ) { if (is_abs(file)==is_abs_s(dir_s)) return mk_lcl(file,dir_s) ; else return file ; } @@ -229,15 +229,15 @@ namespace Disk { // file format is : FileMrkr + file length + file static constexpr char FileMrkr = 0 ; ::string _localize( ::string const& txt , ::string const& dir_s , size_t first_file ) ; // not meant to be used directly - static inline ::string localize( ::string const& txt , ::string const& dir_s={} ) { + inline ::string localize( ::string const& txt , ::string const& dir_s={} ) { if ( size_t pos = txt.find(FileMrkr) ; pos==Npos ) return txt ; // fast path : avoid calling localize else return _localize(txt,dir_s,pos) ; } - static inline ::string localize( ::string&& txt , ::string const& dir_s={} ) { + inline ::string localize( ::string&& txt , ::string const& dir_s={} ) { if ( size_t pos = txt.find(FileMrkr) ; pos==Npos ) return ::move (txt ) ; // fast path : avoid copy else return _localize(txt,dir_s,pos) ; } - static inline ::string mk_file( ::string const& f , Bool3 exists=Maybe ) { + inline ::string mk_file( ::string const& f , Bool3 exists=Maybe ) { ::string pfx(1+sizeof(FileNameIdx),FileMrkr) ; encode_int(&pfx[1],f.size()) ; switch (exists) { diff --git a/src/hash.cc b/src/hash.cc index 38ab431b..2b3a50c0 100644 --- a/src/hash.cc +++ b/src/hash.cc @@ -143,10 +143,10 @@ namespace Hash { return { *reinterpret_cast(_hash) , is_lnk } ; } - static inline void _round1( uint32_t& a , uint32_t b , uint32_t c , uint32_t d , uint32_t m , int s ) { a = b + ::rotl( ((b&c)|((~b)&d)) + a + m , s ) ; } - static inline void _round2( uint32_t& a , uint32_t b , uint32_t c , uint32_t d , uint32_t m , int s ) { a = b + ::rotl( ((d&b)|((~d)&c)) + a + m , s ) ; } - static inline void _round3( uint32_t& a , uint32_t b , uint32_t c , uint32_t d , uint32_t m , int s ) { a = b + ::rotl( (b^c^d ) + a + m , s ) ; } - static inline void _round4( uint32_t& a , uint32_t b , uint32_t c , uint32_t d , uint32_t m , int s ) { a = b + ::rotl( (c^(b|(~d)) ) + a + m , s ) ; } + static void _round1( uint32_t& a , uint32_t b , uint32_t c , uint32_t d , uint32_t m , int s ) { a = b + ::rotl( ((b&c)|((~b)&d)) + a + m , s ) ; } + static void _round2( uint32_t& a , uint32_t b , uint32_t c , uint32_t d , uint32_t m , int s ) { a = b + ::rotl( ((d&b)|((~d)&c)) + a + m , s ) ; } + static void _round3( uint32_t& a , uint32_t b , uint32_t c , uint32_t d , uint32_t m , int s ) { a = b + ::rotl( (b^c^d ) + a + m , s ) ; } + static void _round4( uint32_t& a , uint32_t b , uint32_t c , uint32_t d , uint32_t m , int s ) { a = b + ::rotl( (c^(b|(~d)) ) + a + m , s ) ; } // void _Md5::_update64(const uint32_t _data[BlkSz]) { uint32_t a = _hash[0] ; diff --git a/src/job_exec.cc b/src/job_exec.cc index c013c0d0..5ccad4bc 100644 --- a/src/job_exec.cc +++ b/src/job_exec.cc @@ -25,21 +25,21 @@ using namespace Time ; static constexpr int NConnectionTrials = 3 ; // number of times to try connect when connecting to server -template struct PatternDict { - static constexpr T NotFound = {} ; +struct PatternDict { + static constexpr MatchFlags NotFound = {} ; // services - T const& at(::string const& x) const { + MatchFlags const& at(::string const& x) const { if ( auto it=knowns.find(x) ; it!=knowns.end() ) return it->second ; for( auto const& [p,r] : patterns ) if (+p.match(x)) return r ; /**/ return NotFound ; } - void add( bool star , ::string const& key , T const& val ) { + void add( bool star , ::string const& key , MatchFlags const& val ) { if (star) patterns.emplace_back( RegExpr(key,true/*fast*/,true/*no_group*/) , val ) ; else knowns .emplace ( key , val ) ; } // data - ::umap_s knowns = {} ; - ::vmap patterns = {} ; + ::umap_s knowns = {} ; + ::vmap patterns = {} ; } ; ServerSockFd g_server_fd ; @@ -51,9 +51,10 @@ ::string g_service_end ; SeqId g_seq_id = 0/*garbage*/ ; JobIdx g_job = 0/*garbage*/ ; ::atomic g_killed = false ; // written by thread S and read by main thread -PatternDict g_match_dct ; +PatternDict g_match_dct ; NfsGuard g_nfs_guard ; ::umap_s g_missing_static_targets ; +::vector_s g_washed ; void kill_thread_func(::stop_token stop) { t_thread_key = 'K' ; @@ -96,16 +97,11 @@ bool/*keep_fd*/ handle_server_req( JobServerRpcReq&& jsrr , SlaveSockFd const& ) return false ; } -::pair_s wash(Pdate start) { - Trace trace("wash",start,g_start_info.pre_actions) ; - ::pair/*msg*/> actions = do_file_actions( ::move(g_start_info.pre_actions) , g_nfs_guard , g_start_info.hash_algo ) ; +::pair_s wash() { + Trace trace("wash",g_start_info.pre_actions) ; + ::pair_s actions = do_file_actions( ::move(g_start_info.pre_actions) , g_nfs_guard , g_start_info.hash_algo ) ; trace("unlnks",actions) ; - if (actions.second.second/*ok*/) - for( ::string const& f : actions.first ) { - MatchFlags flags = g_match_dct.at(f) ; - if ( flags.is_target==Yes && static_phony(flags.tflags()) ) g_gather.new_unlnk(start,f) ; // other washed files belong to history, dont record them being erased - } - return actions.second ; + return actions ; } ::map_ss prepare_env(JobRpcReq& end_report) { @@ -231,24 +227,31 @@ Digest analyze( bool at_end , bool killed=false ) { /**/ append_to_string( res.msg , mk_file(file,No|!unlnk) , '\n') ; break ; } - if (ad.write!=No) { + switch (ad.write) { + case No : break ; // /!\ if a write is interrupted, it may continue past the end of the process when accessing a network disk - if ( ad.write==Maybe ) relax.sleep_until() ; // no need to optimize (could compute other crcs while waiting) as this is exceptional - if ( unlnk ) td.crc = Crc::None ; - else if ( killed || !td.tflags[Tflag::Target] ) { FileInfo fi{file} ; td.crc = Crc(fi.tag()) ; td.date = fi.date ; } // no crc if meaningless - else res.crcs.emplace_back(res.targets.size()) ; // record index in res.targets for deferred (parallel) crc computation - } + case Maybe : relax.sleep_until() ; [[fallthrough]] ; // no need to optimize (could compute other crcs while waiting) as this is exceptional + case Yes : + if ( unlnk ) td.crc = Crc::None ; + else if ( killed || !td.tflags[Tflag::Target] ) { FileInfo fi{file} ; td.crc = Crc(fi.tag()) ; td.date = fi.date ; } // no crc if meaningless + else res.crcs.emplace_back(res.targets.size()) ; // record index in res.targets for deferred (parallel) crc computation + break ; + DF} if ( td.tflags[Tflag::Target] && !static_phony(td.tflags) ) { // unless static or phony, a target loses its official status if not actually produced if (ad.write==Yes) { if (unlnk ) td.tflags &= ~Tflag::Target ; } else { if (!is_target(file)) td.tflags &= ~Tflag::Target ; } } - if ( td.tflags[Tflag::Target] && td.tflags[Tflag::Static] ) g_missing_static_targets.erase(file) ; + if ( td.tflags[Tflag::Target] && td.tflags[Tflag::Static] && (td.tflags[Tflag::Phony]||td.crc!=Crc::None) ) g_missing_static_targets.erase(file) ; //vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv res.targets.emplace_back(file,td) ; //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trace("target",ad,td,STR(unlnk),file) ; } } + for( ::string const& t : g_washed ) if (!g_gather.access_map.contains(t)) { + trace("wash",t) ; + res.targets.emplace_back( t , TargetDigest{.extra_tflags=ExtraTflag::Wash,.crc=Crc::None} ) ; + } trace("done",res.deps.size(),res.targets.size(),res.crcs.size(),res.msg) ; return res ; } @@ -406,10 +409,12 @@ int main( int argc , char* argv[] ) { /**/ g_gather.timeout = g_start_info.timeout ; /**/ g_gather.kill_job_cb = kill_job ; // - ::pair_s wash_report = wash(start_overhead) ; + trace("wash",g_start_info.pre_actions) ; + ::pair_s wash_report = do_file_actions( g_washed , ::move(g_start_info.pre_actions) , g_nfs_guard , g_start_info.hash_algo ) ; end_report.msg += wash_report.first ; if (!wash_report.second) { end_report.digest.status = Status::LateLostErr ; goto End ; } g_gather.new_deps( start_overhead , ::move(g_start_info.deps) , g_start_info.stdin ) ; + for( auto const& [t,f] : g_match_dct.knowns ) if (f.is_target==Yes) g_gather.new_unlnk(start_overhead,t) ; // Fd child_stdin ; if (+g_start_info.stdin) child_stdin = open_read(g_start_info.stdin) ; @@ -431,7 +436,6 @@ int main( int argc , char* argv[] ) { struct rusage rsrcs ; getrusage(RUSAGE_CHILDREN,&rsrcs) ; trace("start_job",start_job,"end_job",end_job) ; // - // Digest digest = analyze(true/*at_end*/,killed) ; for( auto const& [f,p] : g_missing_static_targets ) { FileInfo fi{f} ; diff --git a/src/lmakeserver/backend.cc b/src/lmakeserver/backend.cc index eb919e83..b36e71b4 100644 --- a/src/lmakeserver/backend.cc +++ b/src/lmakeserver/backend.cc @@ -65,7 +65,7 @@ namespace Backends { return res ; } - static inline bool _localize( Tag t , ReqIdx ri ) { + static bool _localize( Tag t , ReqIdx ri ) { ::unique_lock lock{Req::s_reqs_mutex} ; // taking Req::s_reqs_mutex is compulsery to derefence req return Req(ri)->options.flags[ReqFlag::Local] || !Backend::s_ready(t) ; // if asked backend is not usable, force local execution } @@ -441,8 +441,8 @@ namespace Backends { // auto it = _s_start_tab.find(+job) ; if (it==_s_start_tab.end() ) { trace("not_in_tab" ) ; return false ; } StartEntry& entry = it->second ; if (entry.conn.seq_id!=jrr.seq_id) { trace("bad_seq_id",entry.conn.seq_id,jrr.seq_id) ; return false ; } - je = JobExec( job , entry.conn.host , entry.start_date ) ; - rsrcs = ::move(entry.rsrcs) ; + je = JobExec( job , entry.conn.host , entry.start_date ) ; + rsrcs = ::move(entry.rsrcs) ; _s_small_ids.release(entry.conn.small_id) ; trace("release_start_tab",job,entry) ; // if we have no fd, job end was invented by heartbeat, no acknowledge @@ -462,8 +462,9 @@ namespace Backends { dep.acquire_crc() ; dd.crc_date(dep) ; } + for( auto& [tn,td] : jrr.digest.targets ) if (td.extra_tflags[ExtraTflag::Wash]) td.date = je.start_date.d ; // adjust wash date as start_date was not available in job ::string jaf = job->ancillary_file() ; - serialize( OFStream(jaf,::ios::app) , JobInfoEnd{jrr} ) ; // /!\ _s_starting_job ensures ancillary file is written by _s_handle_job_start before we append to it + serialize( OFStream(jaf,::ios::app) , JobInfoEnd{jrr} ) ; // /!\ _s_starting_job ensures ancillary file is written by _s_handle_job_start before we append to it job->end_exec() ; je.end_date = file_date(jaf) ; //vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv diff --git a/src/lmakeserver/backends/generic.hh b/src/lmakeserver/backends/generic.hh index 829627eb..9e9a0cd6 100644 --- a/src/lmakeserver/backends/generic.hh +++ b/src/lmakeserver/backends/generic.hh @@ -79,12 +79,12 @@ namespace std { namespace Backends { - template static inline I from_string_rsrc( ::string const& k , ::string const& v ) { + template I from_string_rsrc( ::string const& k , ::string const& v ) { if ( k=="mem" || k=="tmp" ) return from_string_with_units<'M',I>(v) ; else return from_string_with_units< I>(v) ; } - template static inline ::string to_string_rsrc( ::string const& k , I v ) { + template ::string to_string_rsrc( ::string const& k , I v ) { if ( k=="mem" || k=="tmp" ) return to_string_with_units<'M'>(v) ; else return to_string_with_units (v) ; } diff --git a/src/lmakeserver/backends/slurm.cc b/src/lmakeserver/backends/slurm.cc index f3b3b868..fe6b639e 100644 --- a/src/lmakeserver/backends/slurm.cc +++ b/src/lmakeserver/backends/slurm.cc @@ -299,7 +299,7 @@ namespace Backends::Slurm { return os <<')' ; } - static inline void _sort_entry(::string& s) { + static void _sort_entry(::string& s) { if (s.find(',')==Npos) return ; ::vector_s v = split(s,',') ; SWEAR(v.size()>1) ; @@ -393,7 +393,7 @@ namespace Backends::Slurm { } static constexpr char LibSlurm[] = "libslurm.so" ; - template static inline void _load_func( void* handler , T*& dst , const char* name ) { + template void _load_func( void* handler , T*& dst , const char* name ) { dst = reinterpret_cast(::dlsym(handler,name)) ; if (!dst) throw to_string("cannot find ",name," in ",LibSlurm) ; } @@ -418,7 +418,7 @@ namespace Backends::Slurm { trace("done") ; } - static inline ::string slurm_err() { + static ::string slurm_err() { return SlurmApi::strerror(errno) ; } @@ -549,9 +549,9 @@ namespace Backends::Slurm { return { {} , Maybe|completed } ; } - static inline ::string _get_log_dir (JobIdx job) { return Job(job)->ancillary_file(AncillaryTag::Backend) ; } - static inline ::string _get_stderr_path(JobIdx job) { return _get_log_dir(job) + "/stderr" ; } - static inline ::string _get_stdout_path(JobIdx job) { return _get_log_dir(job) + "/stdout" ; } + static ::string _get_log_dir (JobIdx job) { return Job(job)->ancillary_file(AncillaryTag::Backend) ; } + static ::string _get_stderr_path(JobIdx job) { return _get_log_dir(job) + "/stderr" ; } + static ::string _get_stdout_path(JobIdx job) { return _get_log_dir(job) + "/stdout" ; } ::string read_stderr(JobIdx job) { Trace trace(Channel::Backend,"Slurm::read_stderr",job) ; @@ -565,7 +565,7 @@ namespace Backends::Slurm { } } - static inline ::string _cmd_to_string(::vector_s const& cmd_line) { + static ::string _cmd_to_string(::vector_s const& cmd_line) { ::string res = "#!/bin/sh" ; char sep = '\n' ; for ( ::string const& s : cmd_line ) { append_to_string(res,sep,s) ; sep = ' ' ; } diff --git a/src/lmakeserver/caches/dir_cache.cc b/src/lmakeserver/caches/dir_cache.cc index 7e0ddd30..b6f35f92 100644 --- a/src/lmakeserver/caches/dir_cache.cc +++ b/src/lmakeserver/caches/dir_cache.cc @@ -93,7 +93,7 @@ namespace Caches { append_to_string(res,"rule-",::string(rule->cmd_crc)) ; return res ; } - static inline ::string _unique_name( Job job , ::string const& repo ) { return to_string(_unique_name(job),'/',repo) ; } + static ::string _unique_name( Job job , ::string const& repo ) { return to_string(_unique_name(job),'/',repo) ; } // END_OF_VERSIONING void DirCache::_mk_room( Sz old_sz , Sz new_sz ) { @@ -159,9 +159,8 @@ namespace Caches { break ; DF} } - static inline void _copy( ::string const& src_file , Fd dst_at , ::string const& dst_file , bool ud , bool ro ) { _copy( Fd::Cwd , src_file , dst_at , dst_file , ud , ro ) ; } - static inline void _copy( Fd src_at , ::string const& src_file , ::string const& dst_file , bool ud , bool ro ) { _copy( src_at , src_file , Fd::Cwd , dst_file , ud , ro ) ; } - static inline void _copy( ::string const& src_file , ::string const& dst_file , bool ud , bool ro ) { _copy( Fd::Cwd , src_file , Fd::Cwd , dst_file , ud , ro ) ; } + static void _copy( ::string const& src_file , Fd dst_at , ::string const& dst_file , bool ud , bool ro ) { _copy( Fd::Cwd , src_file , dst_at , dst_file , ud , ro ) ; } + static void _copy( Fd src_at , ::string const& src_file , ::string const& dst_file , bool ud , bool ro ) { _copy( src_at , src_file , Fd::Cwd , dst_file , ud , ro ) ; } DirCache::Sz DirCache::_lru_remove(::string const& entry) { SWEAR(entry!=Head) ; diff --git a/src/lmakeserver/global.cc b/src/lmakeserver/global.cc index 331dbc5e..1a082530 100644 --- a/src/lmakeserver/global.cc +++ b/src/lmakeserver/global.cc @@ -14,7 +14,7 @@ namespace Engine { ThreadQueue g_engine_queue ; - static inline ::string _audit_indent( ::string&& t , DepDepth l , char sep=0 ) { + static ::string _audit_indent( ::string&& t , DepDepth l , char sep=0 ) { if (!l) { SWEAR(!sep) ; // cannot have a sep if we have no room to put it return ::move(t) ; diff --git a/src/lmakeserver/global.x.hh b/src/lmakeserver/global.x.hh index 3db3ed61..96ddffa5 100644 --- a/src/lmakeserver/global.x.hh +++ b/src/lmakeserver/global.x.hh @@ -223,16 +223,16 @@ namespace Engine { // sep is put before the last indent level, useful for porcelaine output #define ROC ReqOptions const #define SC ::string const - /**/ void audit( Fd out , ::ostream& log , ROC& , Color , SC& , bool as_is=false , DepDepth =0 , char sep=0 ) ; - static inline void audit( Fd out , ROC& ro , Color c , SC& t , bool a =false , DepDepth l=0 , char sep=0 ) { static OFakeStream fs ; audit(out,fs ,ro,c ,t,a,l,sep) ; } - static inline void audit( Fd out , ::ostream& log , ROC& ro , SC& t , bool a =false , DepDepth l=0 , char sep=0 ) { audit(out,log,ro,Color::None,t,a,l,sep) ; } - static inline void audit( Fd out , ROC& ro , SC& t , bool a =false , DepDepth l=0 , char sep=0 ) { static OFakeStream fs ; audit(out,fs ,ro,Color::None,t,a,l,sep) ; } + /**/ void audit( Fd out , ::ostream& log , ROC& , Color , SC& , bool as_is=false , DepDepth =0 , char sep=0 ) ; + inline void audit( Fd out , ROC& ro , Color c , SC& t , bool a =false , DepDepth l=0 , char sep=0 ) { static OFakeStream fs ; audit(out,fs ,ro,c ,t,a,l,sep) ; } + inline void audit( Fd out , ::ostream& log , ROC& ro , SC& t , bool a =false , DepDepth l=0 , char sep=0 ) { audit(out,log,ro,Color::None,t,a,l,sep) ; } + inline void audit( Fd out , ROC& ro , SC& t , bool a =false , DepDepth l=0 , char sep=0 ) { static OFakeStream fs ; audit(out,fs ,ro,Color::None,t,a,l,sep) ; } #undef SC #undef ROC - template static inline ::string title ( ReqOptions const& , A&&... ) ; - /**/ static inline ::string color_pfx( ReqOptions const& , Color ) ; - /**/ static inline ::string color_sfx( ReqOptions const& , Color ) ; + template ::string title ( ReqOptions const& , A&&... ) ; + inline ::string color_pfx( ReqOptions const& , Color ) ; + inline ::string color_sfx( ReqOptions const& , Color ) ; } @@ -352,24 +352,24 @@ namespace Engine { namespace Engine { - static inline ::string reason_str(JobReason const& reason) { + inline ::string reason_str(JobReason const& reason) { ::string res = reason.msg() ; if (reason.node) append_to_string( res ," : ", Disk::mk_file(Node(reason.node)->name()) ) ; return res ; } - template static inline ::string title( ReqOptions const& ro , A&&... args ) { + template ::string title( ReqOptions const& ro , A&&... args ) { if (ro.reverse_video==Maybe) return {} ; return to_string( "\x1b]0;" , ::forward(args)... , '\a' ) ; } - static inline ::string color_pfx( ReqOptions const& ro , Color color ) { + inline ::string color_pfx( ReqOptions const& ro , Color color ) { if ( color==Color::None || ro.reverse_video==Maybe || ro.flags[ReqFlag::Porcelaine] ) return {} ; ::array const& colors = g_config.colors[+color][ro.reverse_video==Yes] ; return to_string( "\x1b[38;2;" , int(colors[0/*R*/]) ,';', int(colors[1/*G*/]) ,';', int(colors[2/*B*/]) , 'm' ) ; } - static inline ::string color_sfx(ReqOptions const& ro , Color color ) { + inline ::string color_sfx(ReqOptions const& ro , Color color ) { if ( color==Color::None || ro.reverse_video==Maybe || ro.flags[ReqFlag::Porcelaine] ) return {} ; return "\x1b[0m" ; } diff --git a/src/lmakeserver/job.cc b/src/lmakeserver/job.cc index 53001676..1394d876 100644 --- a/src/lmakeserver/job.cc +++ b/src/lmakeserver/job.cc @@ -30,7 +30,7 @@ namespace Engine { for( Node hd=Node(d.first)->dir() ; +hd ; hd = hd->dir() ) if (!locked_dirs.insert(hd).second) break ; // if dir contains a dep, it cannot be rmdir'ed // - // remove old_targets + // remove old targets for( Target t : targets ) { FileActionTag fat = {}/*garbage*/ ; // @@ -352,10 +352,10 @@ namespace Engine { // if ( !lost && status>Status::Early ) { // if early, we have not touched the targets, not even washed them, if lost, old targets are better than new ones // - ::uset from_here ; + ::uset old_targets ; for( Node t : (*this)->targets ) if (t->has_actual_job(*this)) { t->actual_job().clear() ; // ensure targets we no more generate do not keep pointing to us - from_here.insert(t) ; + old_targets.insert(t) ; } // ::vector targets ; targets.reserve(digest.targets.size()) ; @@ -372,7 +372,7 @@ namespace Engine { // if (+crc) { // file dates are very fuzzy and unreliable, at least, filter out targets we generated ourselves - if ( +start_date.d && target->date>start_date.d && !from_here.contains(target) ) { // if no start_date.d, job did not execute, it cannot generate a clash + if ( +start_date.d && target->date>start_date.d && !old_targets.contains(target) ) { // if no start_date.d, job did not execute, it cannot generate a clash // /!\ This may be very annoying ! // A job was running in parallel with us and there was a clash on this target. // There are 2 problems : for us and for them. @@ -1032,7 +1032,7 @@ namespace Engine { // vmap fas = pre_actions(match).first ; ::vmap_s actions ; for( auto [t,a] : fas ) actions.emplace_back( t->name() , a ) ; - ::pair_s dfa_msg = do_file_actions( ::move(actions) , nfs_guard , g_config.hash_algo ).second/*msg*/ ; + ::pair_s dfa_msg = do_file_actions( ::move(actions) , nfs_guard , g_config.hash_algo ) ; // if ( +dfa_msg.first || !dfa_msg.second ) { run_status = RunStatus::Err ; diff --git a/src/lmakeserver/job.x.hh b/src/lmakeserver/job.x.hh index c3bb47ee..44612ab3 100644 --- a/src/lmakeserver/job.x.hh +++ b/src/lmakeserver/job.x.hh @@ -120,9 +120,6 @@ namespace Engine { bool is_static_phony( ) const { return Job::side<1>() ; } void is_static_phony(bool isp) { { if (isp) SWEAR(+*this) ; } Job::side<1>(isp) ; } bool sure ( ) const ; - // - template requires( W>0 && W+LSB<=NGuardBits ) Idx side( ) const = delete ; // { return Job::side( ) ; } - template requires( W>0 && W+LSB<=NGuardBits ) void side(Idx s) = delete ; // { Job::side(s) ; } // services bool produces(Node) const ; } ; @@ -403,7 +400,7 @@ namespace Engine { inline bool JobTgt::produces(Node t) const { if ((*this)->missing() ) return false ; // missing jobs produce nothing if ((*this)->err() ) return true ; // jobs in error are deemed to produce all their potential targets - if (sure() ) return true ; // fast path + if (sure() ) return true ; if (t->has_actual_job(*this)) return t->actual_tflags()[Tflag::Target] ; // . // auto it = ::lower_bound( (*this)->targets , {t,{}} ) ; @@ -444,7 +441,7 @@ namespace Engine { _set_pressure_raw(ri,pressure) ; } - template inline void JobData::audit_end(A&&... args) const { + template void JobData::audit_end(A&&... args) const { JobExec(idx(),New,New).audit_end(::forward(args)...) ; } @@ -476,7 +473,7 @@ namespace Engine { if (&cri==&Req::s_store[+cri.req].jobs.dflt) return req_info(cri.req) ; // allocate else return const_cast(cri) ; // already allocated, no look up } - inline ::vector JobData::reqs() const { return Req::reqs(*this) ; } + inline ::vector JobData::reqs() const { return Req::s_reqs(*this) ; } inline bool JobData::has_req(Req r) const { return Req::s_store[+r].jobs.contains(idx()) ; diff --git a/src/lmakeserver/makefiles.cc b/src/lmakeserver/makefiles.cc index 93ed0a6d..a1ad90ba 100644 --- a/src/lmakeserver/makefiles.cc +++ b/src/lmakeserver/makefiles.cc @@ -105,7 +105,7 @@ namespace Engine::Makefiles { return {} ; } - static inline ::string _deps_file( ::string const& action , bool new_ ) { + static ::string _deps_file( ::string const& action , bool new_ ) { if (new_) return to_string(PrivateAdminDir,'/',action,"_new_deps") ; else return to_string(AdminDir ,'/',action,"_deps" ) ; } diff --git a/src/lmakeserver/node.cc b/src/lmakeserver/node.cc index 86b78460..8bb2a82f 100644 --- a/src/lmakeserver/node.cc +++ b/src/lmakeserver/node.cc @@ -424,7 +424,7 @@ namespace Engine { return ri.done() ; } - static inline bool _must_regenerate( NodeData const& nd , NodeReqInfo& ri ) { + static bool _must_regenerate( NodeData const& nd , NodeReqInfo& ri ) { SWEAR(ri.done_>=ri.goal) ; // must be done to ask for regeneration Job cj = nd.conform_job() ; if (!cj ) return false ; // no hope to regenerate, proceed as a done target @@ -652,7 +652,7 @@ namespace Engine { } } - static inline ::pair _manual_refresh( NodeData& nd , FileInfo const& fi ) { + static ::pair _manual_refresh( NodeData& nd , FileInfo const& fi ) { Manual m = nd.manual(fi) ; if (m(cri) ; // already allocated, no look up } - inline ::vector NodeData::reqs() const { return Req::reqs(*this) ; } + inline ::vector NodeData::reqs() const { return Req::s_reqs(*this) ; } inline bool NodeData::waiting() const { for( Req r : reqs() ) if (c_req_info(r).waiting()) return true ; @@ -495,7 +495,7 @@ namespace Engine { return prio_job_tgts(prio_idx) ; } - template inline void NodeData::add_watcher( ReqInfo& ri , Watcher watcher , RI& wri , CoarseDelay pressure ) { + template void NodeData::add_watcher( ReqInfo& ri , Watcher watcher , RI& wri , CoarseDelay pressure ) { ri.add_watcher(watcher,wri) ; set_pressure(ri,pressure) ; } diff --git a/src/lmakeserver/req.x.hh b/src/lmakeserver/req.x.hh index 0342b084..ceccf448 100644 --- a/src/lmakeserver/req.x.hh +++ b/src/lmakeserver/req.x.hh @@ -44,7 +44,7 @@ namespace Engine { // init static void s_init() {} // statics - template requires(IsOneOf) static ::vector reqs(T const& jn) { // sorted by start + template requires(IsOneOf) static ::vector s_reqs(T const& jn) { // sorted by start ::vector res ; res.reserve(s_reqs_by_start.size()) ; // pessimistic for( Req r : s_reqs_by_start ) if (jn.has_req(r)) res.push_back(r) ; return res ; diff --git a/src/lmakeserver/rule.cc b/src/lmakeserver/rule.cc index c1ae8604..994070e3 100644 --- a/src/lmakeserver/rule.cc +++ b/src/lmakeserver/rule.cc @@ -144,12 +144,9 @@ namespace Engine { case Re : throw to_string("spurious { in ",str) ; DF} } - static inline void _parse_py( ::string const& str , size_t* unnamed_star_idx , ParsePyFuncStem const& cb_stem ) { + static void _parse_py( ::string const& str , size_t* unnamed_star_idx , ParsePyFuncStem const& cb_stem ) { _parse_py( str , unnamed_star_idx , [](::string const&)->void{} , cb_stem ) ; } - static inline void _parse_py( ::string const& str , size_t* unnamed_star_idx , ParsePyFuncFixed const& cb_fixed ) { - _parse_py( str , unnamed_star_idx , cb_fixed , [](::string const&,bool,bool,::string const*)->void{} ) ; - } // star stems are represented by a StemMrkr followed by the stem idx // cb is called on each stem found @@ -174,7 +171,7 @@ namespace Engine { return res ; } // provide shortcut when pos is unused - static inline ::string _subst_target( ::string const& str , ::function const& cb , Escape escape=Escape::None , VarIdx stop_above=-1 ) { + static ::string _subst_target( ::string const& str , ::function const& cb , Escape escape=Escape::None , VarIdx stop_above=-1 ) { return _subst_target( str , [&](FileNameIdx,VarIdx s)->::string { return cb(s) ; } , escape , stop_above ) ; } @@ -188,10 +185,6 @@ namespace Engine { } } } - // provide shortcut when pos is unused - static inline void _parse_target( ::string const& str , ::function const& cb ) { - _parse_target( str , [&](FileNameIdx,VarIdx s)->void { cb(s) ; } ) ; - } template static void _mk_flags( ::string const& key , Sequence const& py_seq , uint8_t n_skip , BitMap& flags , BitMap& extra_flags ) { for( Object const& item : py_seq ) { diff --git a/src/lmakeserver/rule.x.hh b/src/lmakeserver/rule.x.hh index 09f050c8..b3f4a83e 100644 --- a/src/lmakeserver/rule.x.hh +++ b/src/lmakeserver/rule.x.hh @@ -121,7 +121,7 @@ namespace Engine { if (py_dct.contains(key)) return acquire( dst , &py_dct[key] , min , max ) ; else return false ; } - static inline void acquire_env( ::vmap_ss& dst , Py::Dict const& py_dct , ::string const& key ) { acquire_from_dct<::vmap_ss,true/*Env*/>(dst,py_dct,key) ; } + inline void acquire_env( ::vmap_ss& dst , Py::Dict const& py_dct , ::string const& key ) { acquire_from_dct<::vmap_ss,true/*Env*/>(dst,py_dct,key) ; } // ::string subst_fstr( ::string const& fstr , ::umap_s const& var_idxs , VarIdx& n_unnamed ) ; } ; diff --git a/src/lmakeserver/store.x.hh b/src/lmakeserver/store.x.hh index 4eb7b8dd..cd93693c 100644 --- a/src/lmakeserver/store.x.hh +++ b/src/lmakeserver/store.x.hh @@ -369,13 +369,13 @@ namespace Engine::Persistent { for( RuleTgt rt : view() ) if (rt.old()) { pop() ; break ; } } - template static inline void _s_update( Disk& disk , ::uset& mem , bool add , ::vector const& items ) { + template void _s_update( Disk& disk , ::uset& mem , bool add , ::vector const& items ) { bool modified = false ; if (add ) for( Item i : items ) modified |= mem.insert(i).second ; else if (+mem) for( Item i : items ) modified |= mem.erase (i) ; // fast path : no need to update mem if it is already empty if (modified) disk.assign(mk_vector(mem)) ; } - template inline void _s_update( Disk& disk , bool add , ::vector const& items ) { + template void _s_update( Disk& disk , bool add , ::vector const& items ) { ::uset mem = mk_uset(disk) ; _s_update(disk,mem,add,items) ; } @@ -391,10 +391,10 @@ namespace Engine::Persistent { // inline Job JobBase::s_idx(JobData const& jd) { return _job_file.idx(jd) ; } // cxtors & casts - template inline JobBase::JobBase( NewType , A&&... args ) { // 1st arg is only used to disambiguate + template JobBase::JobBase( NewType , A&&... args ) { // 1st arg is only used to disambiguate *this = _job_file.emplace( Name() , ::forward(args)... ) ; } - template inline JobBase::JobBase( ::pair_ss const& name_sfx , bool new_ , A&&... args ) { // jobs are only created in main thread, so no locking is necessary + template JobBase::JobBase( ::pair_ss const& name_sfx , bool new_ , A&&... args ) { // jobs are only created in main thread, so no locking is necessary Name name_ = _name_file.insert(name_sfx.first,name_sfx.second) ; *this = _name_file.c_at(+name_).job() ; if (+*this) { diff --git a/src/process.hh b/src/process.hh index 7025f583..e4abec81 100644 --- a/src/process.hh +++ b/src/process.hh @@ -37,7 +37,7 @@ struct Pipe { Fd write ; // write side of the pipe } ; -static inline bool/*all_done*/ set_sig( ::vector const& sigs , bool block ) { +inline bool/*all_done*/ set_sig( ::vector const& sigs , bool block ) { sigset_t new_mask ; sigset_t old_mask ; ::sigemptyset(&new_mask) ; @@ -48,7 +48,7 @@ static inline bool/*all_done*/ set_sig( ::vector const& sigs , bool block ) for( int s : sigs ) if (::sigismember(&old_mask,s)==block) return false ; return true ; } -static inline Fd open_sig_fd(::vector const& sigs) { +inline Fd open_sig_fd(::vector const& sigs) { swear_prod(set_sig(sigs,true/*block*/),"some of signals",sigs,"are already blocked") ; // sigset_t mask ; @@ -57,12 +57,12 @@ static inline Fd open_sig_fd(::vector const& sigs) { // return ::signalfd( -1 , &mask , SFD_CLOEXEC ) ; } -static inline void close_sig_fd( Fd fd , ::vector const& sigs ) { +inline void close_sig_fd( Fd fd , ::vector const& sigs ) { fd.close() ; set_sig(sigs,false/*block*/) ; } -static inline bool is_sig_sync(int sig) { +inline bool is_sig_sync(int sig) { switch (sig) { case SIGILL : case SIGTRAP : @@ -74,7 +74,7 @@ static inline bool is_sig_sync(int sig) { } } -static inline ::string wstatus_str(int wstatus) { +inline ::string wstatus_str(int wstatus) { if (WIFEXITED (wstatus)) return WEXITSTATUS(wstatus) ? to_string("exit ",WEXITSTATUS(wstatus)) : "ok"s ; if (WIFSIGNALED(wstatus)) return to_string("signal ",WTERMSIG(wstatus),'-',::strsignal(WTERMSIG(wstatus))) ; else return "??" ; diff --git a/src/py.hh b/src/py.hh index 980719d2..8a5d56bf 100644 --- a/src/py.hh +++ b/src/py.hh @@ -50,14 +50,14 @@ namespace Py { // functions // - template static inline T const* _chk (T const * o) { if ( o && !o->qualify() ) throw to_string("not a ",o->type_name()) ; return o ; } - template static inline T * _chk (T * o) { if ( o && !o->qualify() ) throw to_string("not a ",o->type_name()) ; return o ; } - template static inline T * from_py(PyObject* o) { T* res = static_cast(o) ; _chk(res) ; return res ; } + template T const* _chk (T const * o) { if ( o && !o->qualify() ) throw to_string("not a ",o->type_name()) ; return o ; } + template T * _chk (T * o) { if ( o && !o->qualify() ) throw to_string("not a ",o->type_name()) ; return o ; } + template T * from_py(PyObject* o) { T* res = static_cast(o) ; _chk(res) ; return res ; } - static inline void py_err_clear () { PyErr_Clear () ; } - static inline bool py_err_occurred() { return PyErr_Occurred() ; } + inline void py_err_clear () { PyErr_Clear () ; } + inline bool py_err_occurred() { return PyErr_Occurred() ; } // - template static inline T& py_get_sys(::string const& name) { + template T& py_get_sys(::string const& name) { PyObject* v = PySys_GetObject(const_cast(name.c_str())) ; if (!v) throw to_string("cannot find sys.",name) ; return *from_py(v) ; @@ -67,7 +67,7 @@ namespace Py { ::string py_err_str_clear() ; // like PyErr_Print, but return text instead of printing it (Python API provides no means to do this !) // - static inline nullptr_t py_err_set( Exception e , ::string const& txt ) { + inline nullptr_t py_err_set( Exception e , ::string const& txt ) { static PyObject* s_exc_tab[] = { PyExc_RuntimeError // RuntimeErr , PyExc_TypeError // TypeErr @@ -574,7 +574,7 @@ namespace Py { // Object // - template inline Ptr Object::get_attr(::string const& attr) const { + template Ptr Object::get_attr(::string const& attr) const { PyObject* val = PyObject_GetAttrString(to_py(),attr.c_str()) ; if (!val) throw py_err_str_clear() ; return val ; diff --git a/src/rpc_client.hh b/src/rpc_client.hh index fcad3336..b2c793cd 100644 --- a/src/rpc_client.hh +++ b/src/rpc_client.hh @@ -41,7 +41,7 @@ ENUM( ReqKey // PER_CMD : add key as necessary (you may share with other comma , Stdout // if proc==Show , Targets // if proc==Show ) -static inline bool is_mark_glb(ReqKey key) { +inline bool is_mark_glb(ReqKey key) { switch (key) { case ReqKey::Clear : case ReqKey::List : return true ; diff --git a/src/rpc_job.cc b/src/rpc_job.cc index 9b01d4ea..6e20b379 100644 --- a/src/rpc_job.cc +++ b/src/rpc_job.cc @@ -21,11 +21,10 @@ ::ostream& operator<<( ::ostream& os , FileAction const& fa ) { return os <<')' ; } -::pair/*msg*/> do_file_actions( ::vmap_s&& pre_actions , NfsGuard& nfs_guard , Algo ha ) { - ::uset_s keep_dirs ; - ::vector_s unlnks ; - ::string msg ; - bool ok = true ; +::pair_s do_file_actions( ::vector_s* unlnks , ::vmap_s&& pre_actions , NfsGuard& nfs_guard , Algo ha ) { + ::uset_s keep_dirs ; + ::string msg ; + bool ok = true ; // for( auto const& [f,a] : pre_actions ) { // pre_actions are adequately sorted SWEAR(+f) ; // acting on root dir is non-sense @@ -43,10 +42,10 @@ ::pair/*msg*/> do_file_actions( ::vmap_spush_back(f) ; + ok &= done ; } break ; case FileActionTag::Rmdir : if (!keep_dirs.contains(f)) @@ -55,7 +54,7 @@ ::pair/*msg*/> do_file_actions( ::vmap_s/*msg*/> do_file_actions( ::vmap_s&& pre_actions , Disk::NfsGuard& nfs_guard , Algo ) ; +/**/ ::pair_s do_file_actions( ::vector_s* unlnks/*out*/ , ::vmap_s&& , Disk::NfsGuard& , Algo ) ; +inline ::pair_s do_file_actions( ::vector_s& unlnks/*out*/ , ::vmap_s&& pa , Disk::NfsGuard& ng , Algo a ) { return do_file_actions(&unlnks,::move(pa),ng,a) ; } +inline ::pair_s do_file_actions( ::vmap_s&& pa , Disk::NfsGuard& ng , Algo a ) { return do_file_actions(nullptr,::move(pa),ng,a) ; } ENUM_2( Dflag // flags for deps , NRule = Required // number of Dflag's allowed in rule definition @@ -99,7 +101,7 @@ static constexpr char TflagChars[] = { } ; static_assert(::size(TflagChars)==N) ; using Tflags = BitMap ; -static inline bool static_phony(Tflags tf) { +inline bool static_phony(Tflags tf) { return tf[Tflag::Target] && (tf[Tflag::Static]||tf[Tflag::Phony]) ; } @@ -109,12 +111,14 @@ ENUM_1( ExtraTflag , Ignore , SourceOk // ok to overwrite source files , Allow // writing to this target is allowed (for use in clmake.target and ltarget) +, Wash // target was unlinked when washing before job execution ) static constexpr char ExtraTflagChars[] = { 0 // Top , 'I' // Ignore , 's' // SourceOk , 'a' // Allow +, 0 // Wash } ; static_assert(::size(ExtraTflagChars)==N) ; using ExtraTflags = BitMap ; @@ -250,8 +254,8 @@ ENUM_3( Status // result of job execution , Ok // job execution ended successfully , Err // job execution ended in error ) -static inline bool is_lost(Status s) { return s<=Status::LateLostErr && s>=Status::EarlyLost ; } -static inline Bool3 is_ok (Status s) { +inline bool is_lost(Status s) { return s<=Status::LateLostErr && s>=Status::EarlyLost ; } +inline Bool3 is_ok (Status s) { static constexpr Bool3 IsOkTab[] = { Maybe // New , Maybe // EarlyChkDeps @@ -269,7 +273,7 @@ static inline Bool3 is_ok (Status s) { static_assert(sizeof(IsOkTab)==N) ; return IsOkTab[+s] ; } -static inline Status mk_err(Status s) { +inline Status mk_err(Status s) { switch (s) { case Status::New : return Status::EarlyErr ; case Status::EarlyLost : return Status::EarlyLostErr ; @@ -277,7 +281,7 @@ static inline Status mk_err(Status s) { case Status::Ok : return Status::Err ; DF} } -static inline JobReasonTag mk_reason(Status s) { +inline JobReasonTag mk_reason(Status s) { static constexpr JobReasonTag ReasonTab[] = { JobReasonTag::New // New , JobReasonTag::ChkDeps // EarlyChkDeps diff --git a/src/serialize.hh b/src/serialize.hh index 4b089e69..03e30f34 100644 --- a/src/serialize.hh +++ b/src/serialize.hh @@ -17,24 +17,24 @@ template concept HasSerdeser = !HasSerdes && requires( T x , ::istre template concept Serializable = HasSerdes || HasSerdeser ; // serdes method should be const when serializing but is not because C++ does not let constness be template arg dependent -/**/ static inline void serdes( ::ostream& ) { } -/**/ static inline void serdes( ::istream& ) { } -template static inline void serdes( ::ostream& os , T const& x ) { const_cast(x).serdes(os) ; } -template static inline void serdes( ::istream& is , T & x ) { x .serdes(is) ; } -template static inline void serdes( ::ostream& os , T const& x ) { Serdeser::s_serdes(os,x) ; } -template static inline void serdes( ::istream& is , T & x ) { Serdeser::s_serdes(is,x) ; } -template< Serializable T1 , Serializable T2 , Serializable... Ts > static inline void serdes( ::ostream& os , T1 const& x1 , T2 const& x2 , Ts const&... xs ) { serdes(os,x1) ; serdes(os,x2,xs...) ; } -template< Serializable T1 , Serializable T2 , Serializable... Ts > static inline void serdes( ::istream& is , T1 & x1 , T2 & x2 , Ts &... xs ) { serdes(is,x1) ; serdes(is,x2,xs...) ; } +inline void serdes( ::ostream& ) { } +inline void serdes( ::istream& ) { } +template void serdes( ::ostream& os , T const& x ) { const_cast(x).serdes(os) ; } +template void serdes( ::istream& is , T & x ) { x .serdes(is) ; } +template void serdes( ::ostream& os , T const& x ) { Serdeser::s_serdes(os,x) ; } +template void serdes( ::istream& is , T & x ) { Serdeser::s_serdes(is,x) ; } +template< Serializable T1 , Serializable T2 , Serializable... Ts > void serdes( ::ostream& os , T1 const& x1 , T2 const& x2 , Ts const&... xs ) { serdes(os,x1) ; serdes(os,x2,xs...) ; } +template< Serializable T1 , Serializable T2 , Serializable... Ts > void serdes( ::istream& is , T1 & x1 , T2 & x2 , Ts &... xs ) { serdes(is,x1) ; serdes(is,x2,xs...) ; } // -template static inline void serialize ( ::ostream& os , T const& x ) { serdes(os ,x ) ; os.flush() ; } -template static inline ::string serialize ( T const& x ) { OStringStream res ; serdes(res,x ) ; return res.str() ; } -template static inline void deserialize( ::istream& is , T & x ) { serdes(is ,x ) ; } -template static inline T deserialize( ::istream& is ) { T res ; serdes(is ,res) ; return res ; } +template void serialize ( ::ostream& os , T const& x ) { serdes(os ,x ) ; os.flush() ; } +template ::string serialize ( T const& x ) { OStringStream res ; serdes(res,x ) ; return res.str() ; } +template void deserialize( ::istream& is , T & x ) { serdes(is ,x ) ; } +template T deserialize( ::istream& is ) { T res ; serdes(is ,res) ; return res ; } // -template static inline void serialize ( ::ostream&& os , T const& x ) { serialize (os ,x) ; } -template static inline void deserialize( ::istream&& is , T & x ) { deserialize(is ,x) ; } -template static inline T deserialize( ::istream&& is ) { return deserialize(is ) ; } -template static inline T deserialize( ::string const& s ) { return deserialize(IStringStream(s) ) ; } +template void serialize ( ::ostream&& os , T const& x ) { serialize (os ,x) ; } +template void deserialize( ::istream&& is , T & x ) { deserialize(is ,x) ; } +template T deserialize( ::istream&& is ) { return deserialize(is ) ; } +template T deserialize( ::string const& s ) { return deserialize(IStringStream(s) ) ; } // make objects hashable as soon as they define serdes(::ostream) && serdes(::istream) // as soon as a class T is serializable, you can simply use ::set, ::uset, ::map or ::umap diff --git a/src/store/prefix.hh b/src/store/prefix.hh index e47f7f41..5dc3a6a5 100644 --- a/src/store/prefix.hh +++ b/src/store/prefix.hh @@ -33,16 +33,16 @@ namespace Store { template using VecStr = ::conditional_t,Vec> ; template using ItemChar = ::conditional_t, Char > ; // - template inline void append( ::vector & res , Char const* from , size_t sz ) { for( Char const& c : ::c_vector_view(from,sz) ) res.push_back(c) ; } - template inline void append( ::basic_string>& res , Char const* from , size_t sz ) { res.append(from,sz) ; } + template void append( ::vector & res , Char const* from , size_t sz ) { for( Char const& c : ::c_vector_view(from,sz) ) res.push_back(c) ; } + template void append( ::basic_string>& res , Char const* from , size_t sz ) { res.append(from,sz) ; } - template inline Char const& char_at( VecView const& name , size_t pos ) { + template Char const& char_at( VecView const& name , size_t pos ) { return name[ Reverse ? name.size()-1-pos : pos ] ; } - template inline Char const& char_at( VecView const& name , VecView const& psfx , size_t pos ) { + template Char const& char_at( VecView const& name , VecView const& psfx , size_t pos ) { return pos(name,pos) : char_at(psfx,pos-name.size()) ; } - template inline size_t size( VecView const& name , VecView const& psfx ) { + template size_t size( VecView const& name , VecView const& psfx ) { return name.size() + psfx.size() ; } @@ -89,8 +89,8 @@ namespace Store { // data uint8_t val ; } ; - static inline KindIterator begin(Nxt n) { return n ; } - static inline KindIterator end (Nxt ) { return Nxt(ItemKind::Terminal) ; } + inline KindIterator begin(Nxt n) { return n ; } + inline KindIterator end (Nxt ) { return Nxt(ItemKind::Terminal) ; } template struct ItemBase { static_assert(IsTrivial) ; diff --git a/src/store/struct.hh b/src/store/struct.hh index fb73826b..f4ee85ac 100644 --- a/src/store/struct.hh +++ b/src/store/struct.hh @@ -49,11 +49,11 @@ namespace Store { using Base::writable ; // statics private : - static constexpr size_t _offset0 = sizeof(StructHdr)-sizeof(DataNv) ; // unsigned types handle negative values modulo 2^n, which is ok - static constexpr size_t _offset(Sz idx) requires(HasFile) { SWEAR(idx) ; return _offset0 + sizeof(DataNv)*idx ; } + static constexpr size_t _Offset0 = sizeof(StructHdr)-sizeof(DataNv) ; // unsigned types handle negative values modulo 2^n, which is ok + static constexpr size_t _s_offset(Sz idx) requires(HasFile) { SWEAR(idx) ; return _Offset0 + sizeof(DataNv)*idx ; } // cxtors & casts template void _alloc_hdr(A&&... hdr_args) requires(HasFile) { - Base::expand(_offset(1)) ; // 1 is the first used idx + Base::expand(_s_offset(1)) ; // 1 is the first used idx new(&_struct_hdr()) StructHdr{::forward(hdr_args)...} ; } public : @@ -66,7 +66,7 @@ namespace Store { template void init( NewType , A&&... hdr_args ) requires( HasFile) { init( "" , true , ::forward(hdr_args)... ) ; } /**/ void init( ::string const& /*name*/ , bool /*writable*/ ) requires(!HasFile) {} template void init( ::string const& name , bool writable , A&&... hdr_args ) requires( HasFile) { - Base::init( name , _offset(HasData?lsb_msk(NBits):1) , writable ) ; + Base::init( name , _s_offset(HasData?lsb_msk(NBits):1) , writable ) ; if (Base::operator+()) return ; SWEAR(writable) ; _alloc_hdr(::forward(hdr_args)...) ; @@ -78,10 +78,10 @@ namespace Store { HdrNv const& hdr ( ) const requires(HasHdr ) { return _struct_hdr().hdr ; } HdrNv & hdr ( ) requires(HasHdr ) { SWEAR(writable) ; return _struct_hdr().hdr ; } HdrNv const& c_hdr ( ) const requires(HasHdr ) { return _struct_hdr().hdr ; } - DataNv const& at (Idx idx) const requires(HasData) { return *reinterpret_cast(base+_offset(+idx)) ; } - DataNv & at (Idx idx) requires(HasData) { SWEAR(writable) ; return *reinterpret_cast(base+_offset(+idx)) ; } - DataNv const& c_at (Idx idx) const requires(HasData) { return *reinterpret_cast(base+_offset(+idx)) ; } - Idx idx (DataNv const& at ) const requires(HasData) { return Idx(&at-reinterpret_cast(base+_offset0)) ; } + DataNv const& at (Idx idx) const requires(HasData) { return *reinterpret_cast(base+_s_offset(+idx)) ; } + DataNv & at (Idx idx) requires(HasData) { SWEAR(writable) ; return *reinterpret_cast(base+_s_offset(+idx)) ; } + DataNv const& c_at (Idx idx) const requires(HasData) { return *reinterpret_cast(base+_s_offset(+idx)) ; } + Idx idx (DataNv const& at ) const requires(HasData) { return Idx(&at-reinterpret_cast(base+_Offset0)) ; } void clear (Idx idx) requires(HasData) { if (!idx) return ; at(idx) = {} ; } private : StructHdr const& _struct_hdr() const requires(HasFile) { return *reinterpret_cast(base) ; } @@ -99,7 +99,7 @@ namespace Store { } void chk() const requires(HasFile) { Base::chk() ; - if (size()) throw_unless( _offset(size())<=Base::size , "logical size is larger than physical size" ) ; + if (size()) throw_unless( _s_offset(size())<=Base::size , "logical size is larger than physical size" ) ; } protected : void _clear() { @@ -115,10 +115,10 @@ namespace Store { { ULock lock{_mutex} ; old_sz = size() ; new_sz = old_sz + sz ; - swear( new_sz>=old_sz && new_sz<=lsb_msk(NBits) ,"index overflow on ",name) ; // ensure no arithmetic overflow before checking capacity - Base::expand(_offset(new_sz)) ; - fence() ; // update state when it is legal to do so - _size() = new_sz ; // once allocation is done, no reason to maintain lock + swear( new_sz>=old_sz && new_sz<=lsb_msk(NBits) ,"index overflow on ",name) ; // ensure no arithmetic overflow before checking capacity + Base::expand(_s_offset(new_sz)) ; + fence() ; // update state when it is legal to do so + _size() = new_sz ; // once allocation is done, no reason to maintain lock } Idx res{old_sz} ; new(&at(res)) Data(::forward(args)...) ; diff --git a/src/time.hh b/src/time.hh index a2efb53b..eba87317 100644 --- a/src/time.hh +++ b/src/time.hh @@ -309,9 +309,9 @@ namespace Time { TimeSpec ts(*this) ; ::nanosleep(&ts,nullptr) ; } - template requires(::is_arithmetic_v) inline constexpr Delay Delay::operator*(T f) const { return Delay(New,int64_t(_val* f )) ; } - template requires(::is_signed_v ) inline constexpr Delay Delay::operator/(T f) const { return Delay(New,int64_t(_val/ f )) ; } - template requires(::is_unsigned_v ) inline constexpr Delay Delay::operator/(T f) const { return Delay(New,int64_t(_val/::make_signed_t(f))) ; } + template requires(::is_arithmetic_v) constexpr Delay Delay::operator*(T f) const { return Delay(New,int64_t(_val* f )) ; } + template requires(::is_signed_v ) constexpr Delay Delay::operator/(T f) const { return Delay(New,int64_t(_val/ f )) ; } + template requires(::is_unsigned_v ) constexpr Delay Delay::operator/(T f) const { return Delay(New,int64_t(_val/::make_signed_t(f))) ; } // // Pdate diff --git a/src/trace.hh b/src/trace.hh index 5444a885..fbcb32df 100644 --- a/src/trace.hh +++ b/src/trace.hh @@ -8,7 +8,7 @@ #include "fd.hh" #include "time.hh" -#define STR(x) Trace::str((x),#x) +#define STR(x) Trace::s_str((x),#x) extern ::string* g_trace_file ; // pointer to avoid init/fini order hazards, relative to admin dir @@ -25,7 +25,7 @@ static constexpr Channels DfltChannels = ~Channels() ; // statics static void s_start (Channels=DfltChannels) {} static void s_new_trace_file(::string const& ) {} - template static ::string str( T const& , ::string const& ) { return {} ; } + template static ::string s_str( T const& , ::string const& ) { return {} ; } // static data static bool s_backup_trace ; static ::atomic s_sz ; @@ -51,23 +51,23 @@ static constexpr Channels DfltChannels = ~Channels() ; static void _s_open() ; // public : - template static ::string str( T const& v , ::string const& s ) { return s+"="+to_string(v) ; } - /**/ static ::string str( bool v , ::string const& s ) { return v ? s : '!'+s ; } - /**/ static ::string str( uint8_t v , ::string const& s ) { return str(int(v),s) ; } // avoid confusion with char - /**/ static ::string str( int8_t v , ::string const& s ) { return str(int(v),s) ; } // avoid confusion with char + template static ::string s_str( T const& v , ::string const& s ) { return s+"="+to_string(v) ; } + /**/ static ::string s_str( bool v , ::string const& s ) { return v ? s : '!'+s ; } + /**/ static ::string s_str( uint8_t v , ::string const& s ) { return s_str(int(v),s) ; } // avoid confusion with char + /**/ static ::string s_str( int8_t v , ::string const& s ) { return s_str(int(v),s) ; } // avoid confusion with char // static data static bool s_backup_trace ; - static ::atomic s_sz ; // max overall size of trace, beyond, trace wraps + static ::atomic s_sz ; // max overall size of trace, beyond, trace wraps static Channels s_channels ; private : - static size_t _s_pos ; // current line number - static bool _s_ping ; // ping-pong to distinguish where trace stops in the middle of a trace + static size_t _s_pos ; // current line number + static bool _s_ping ; // ping-pong to distinguish where trace stops in the middle of a trace static Fd _s_fd ; static ::mutex _s_mutex ; // static thread_local int _t_lvl ; - static thread_local bool _t_hide ; // if true <=> do not generate trace - static thread_local OStringStream* _t_buf ; // pointer to avoid init/fini order hazards + static thread_local bool _t_hide ; // if true <=> do not generate trace + static thread_local OStringStream* _t_buf ; // pointer to avoid init/fini order hazards // // cxtors & casts public : @@ -85,10 +85,10 @@ static constexpr Channels DfltChannels = ~Channels() ; private : template void _record(Ts const&... ) ; template void _output(T const& x) { *_t_buf << x ; } - template void _output(::string const& x) { *_t_buf << (P?mk_printable(x):x) ; } // make printable if asked to do so - template void _output(uint8_t x) { *_t_buf << int(x) ; } // avoid confusion with char - template void _output(int8_t x) { *_t_buf << int(x) ; } // avoid confusion with char - template void _output(bool x) = delete ; // bool is not explicit enough, use strings + template void _output(::string const& x) { *_t_buf << (P?mk_printable(x):x) ; } // make printable if asked to do so + template void _output(uint8_t x) { *_t_buf << int(x) ; } // avoid confusion with char + template void _output(int8_t x) { *_t_buf << int(x) ; } // avoid confusion with char + template void _output(bool x) = delete ; // bool is not explicit enough, use strings // data SaveInc _sav_lvl ; Save _sav_hide ; diff --git a/src/utils.hh b/src/utils.hh index 6c0a67ad..0a3e07c3 100644 --- a/src/utils.hh +++ b/src/utils.hh @@ -71,9 +71,9 @@ template using AsChar = ::conditional_t,T,char> ; template concept IsA = ::is_same_v,remove_const_t> || ::is_base_of_v,remove_const_t> ; template concept IsNotVoid = !::is_void_v ; -template static inline constexpr T copy (T const& x) { return x ; } -template static inline constexpr T & ref (T && x) { return x ; } -template static inline constexpr T const& constify(T const& x) { return x ; } +template constexpr T copy (T const& x) { return x ; } +template constexpr T & ref (T && x) { return x ; } +template constexpr T const& constify(T const& x) { return x ; } // // std lib name simplification @@ -111,20 +111,20 @@ template using vmap = ::vector template< class V > using vmap_s = ::vmap ; /**/ using vmap_ss = ::vmap_s < string > ; -template static inline constexpr bool operator+(::array const& ) { return N ; } -template static inline constexpr bool operator!(::array const& a) { return !+a ; } -template static inline constexpr bool operator+(::pair const& p) { return +p.first||+p.second ; } -template static inline constexpr bool operator!(::pair const& p) { return !+p ; } -template static inline constexpr bool operator+(::map const& m) { return !m.empty() ; } -template static inline constexpr bool operator!(::map const& m) { return !+m ; } -template static inline constexpr bool operator+(::umap const& m) { return !m.empty() ; } -template static inline constexpr bool operator!(::umap const& m) { return !+m ; } -template static inline constexpr bool operator+(::set const& s) { return !s.empty() ; } -template static inline constexpr bool operator!(::set const& s) { return !+s ; } -template static inline constexpr bool operator+(::uset const& s) { return !s.empty() ; } -template static inline constexpr bool operator!(::uset const& s) { return !+s ; } -template static inline constexpr bool operator+(::vector const& v) { return !v.empty() ; } -template static inline constexpr bool operator!(::vector const& v) { return !+v ; } +template constexpr bool operator+(::array const& ) { return N ; } +template constexpr bool operator!(::array const& a) { return !+a ; } +template constexpr bool operator+(::pair const& p) { return +p.first||+p.second ; } +template constexpr bool operator!(::pair const& p) { return !+p ; } +template constexpr bool operator+(::map const& m) { return !m.empty() ; } +template constexpr bool operator!(::map const& m) { return !+m ; } +template constexpr bool operator+(::umap const& m) { return !m.empty() ; } +template constexpr bool operator!(::umap const& m) { return !+m ; } +template constexpr bool operator+(::set const& s) { return !s.empty() ; } +template constexpr bool operator!(::set const& s) { return !+s ; } +template constexpr bool operator+(::uset const& s) { return !s.empty() ; } +template constexpr bool operator!(::uset const& s) { return !+s ; } +template constexpr bool operator+(::vector const& v) { return !v.empty() ; } +template constexpr bool operator!(::vector const& v) { return !+v ; } #define VT(T) typename T::value_type @@ -186,7 +186,7 @@ template VT(T) max ( T const& x #undef TVT -template static inline T& grow( ::vector& v , uint32_t i ) { +template T& grow( ::vector& v , uint32_t i ) { if(i>=v.size()) v.resize(i+1) ; return v[i] ; } @@ -210,11 +210,11 @@ protected : using OFakeStream = FakeStream<::ostream> ; using IFakeStream = FakeStream<::istream> ; -static inline void _set_cloexec(::filebuf* fb) { +inline void _set_cloexec(::filebuf* fb) { int fd = np_get_fd(*fb) ; if (fd>=0) ::fcntl(fd,F_SETFD,FD_CLOEXEC) ; } -static inline void sanitize(::ostream& os) { +inline void sanitize(::ostream& os) { os.exceptions(~os.goodbit) ; os<<::left<<::boolalpha ; } @@ -253,25 +253,25 @@ struct IStringStream : ::istringstream { // string // -static inline bool operator+(::string const& s) { return !s.empty() ; } -static inline bool operator!(::string const& s) { return !+s ; } -static inline bool operator+(::string_view const& s) { return !s.empty() ; } -static inline bool operator!(::string_view const& s) { return !+s ; } +inline bool operator+(::string const& s) { return !s.empty() ; } +inline bool operator!(::string const& s) { return !+s ; } +inline bool operator+(::string_view const& s) { return !s.empty() ; } +inline bool operator!(::string_view const& s) { return !+s ; } static constexpr size_t Npos = ::string::npos ; -template static inline ::string to_string(A const&... args) { +template ::string to_string(A const&... args) { OStringStream res ; [[maybe_unused]] bool _[] = { false , (res< S> static inline I from_string( S const& txt , bool empty_ok=false , bool hex=false ) { +template<::integral I,IsOneOf<::string,::string_view> S> I from_string( S const& txt , bool empty_ok=false , bool hex=false ) { static constexpr bool IsBool = is_same_v ; if ( empty_ok && !txt ) return 0 ; ::conditional_t res = 0/*garbage*/ ; @@ -282,9 +282,9 @@ template<::integral I,IsOneOf<::string,::string_view> S> static inline I from_st if ( rc.ec!=::errc{} ) throw ::make_error_code(rc.ec).message() ; else return res ; } -template<::integral I> static inline I from_string( const char* txt , bool empty_ok=false , bool hex=false ) { return from_string( ::string_view(txt,strlen(txt)) , empty_ok , hex ) ; } +template<::integral I> I from_string( const char* txt , bool empty_ok=false , bool hex=false ) { return from_string( ::string_view(txt,strlen(txt)) , empty_ok , hex ) ; } // -template<::floating_point F,IsOneOf<::string,::string_view> S> static inline F from_string( S const& txt , bool empty_ok=false ) { +template<::floating_point F,IsOneOf<::string,::string_view> S> F from_string( S const& txt , bool empty_ok=false ) { if ( empty_ok && !txt ) return 0 ; F res = 0/*garbage*/ ; // vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv @@ -293,14 +293,14 @@ template<::floating_point F,IsOneOf<::string,::string_view> S> static inline F f if (rc.ec!=::errc{}) throw ::make_error_code(rc.ec).message() ; else return res ; } -template<::floating_point F> static inline F from_string( const char* txt , bool empty_ok=false ) { return from_string( ::string_view(txt,strlen(txt)) , empty_ok ) ; } +template<::floating_point F> F from_string( const char* txt , bool empty_ok=false ) { return from_string( ::string_view(txt,strlen(txt)) , empty_ok ) ; } ::string mk_py_str (::string const&) ; ::string mk_json_str (::string const&) ; ::string mk_shell_str(::string const&) ; // ::isspace is too high level as it accesses environment, which may not be available during static initialization -static inline constexpr bool is_space(char c) { +inline constexpr bool is_space(char c) { switch (c) { case '\f' : case '\n' : @@ -313,32 +313,32 @@ static inline constexpr bool is_space(char c) { } // ::isprint is too high level as it accesses environment, which may not be available during static initialization -static inline constexpr bool is_printable(char c) { +inline constexpr bool is_printable(char c) { return uint8_t(c)>=0x20 && uint8_t(c)<=0x7e ; } -static inline bool is_printable(::string const& s) { +inline bool is_printable(::string const& s) { for( char c : s ) if (!is_printable(c)) return false ; /**/ return true ; } -template ::string mk_printable(::string const& ) ; -template static inline ::string mk_printable(::string && txt) { +template ::string mk_printable(::string const& ) ; +template ::string mk_printable(::string && txt) { for( char c : txt ) if ( !is_printable(c) || (Delimiter&&c==Delimiter) ) return mk_printable(txt) ; return ::move(txt) ; // fast path : avoid analysis & copy } template ::pair_s parse_printable( ::string const& , size_t pos=0 ) ; -static inline void set_nl (::string & txt) { if ( +txt && txt.back()!='\n' ) txt += '\n' ; } -static inline void set_no_nl (::string & txt) { if ( +txt && txt.back()=='\n' ) txt.pop_back() ; } -static inline ::string ensure_nl (::string && txt) { set_nl (txt) ; return txt ; } -static inline ::string ensure_no_nl(::string && txt) { set_no_nl(txt) ; return txt ; } -static inline ::string ensure_nl (::string const& txt) { return ensure_nl (::copy(txt)) ; } -static inline ::string ensure_no_nl(::string const& txt) { return ensure_no_nl(::copy(txt)) ; } - -template static inline void _append_to_string( ::string& dst , T&& x ) { dst += to_string(::forward(x)) ; } -/**/ static inline void _append_to_string( ::string& dst , ::string const& s ) { dst += s ; } // fast path -/**/ static inline void _append_to_string( ::string& dst , const char* s ) { dst += s ; } // . -/**/ static inline void _append_to_string( ::string& dst , char c ) { dst += c ; } // . +inline void set_nl (::string & txt) { if ( +txt && txt.back()!='\n' ) txt += '\n' ; } +inline void set_no_nl (::string & txt) { if ( +txt && txt.back()=='\n' ) txt.pop_back() ; } +inline ::string ensure_nl (::string && txt) { set_nl (txt) ; return txt ; } +inline ::string ensure_no_nl(::string && txt) { set_no_nl(txt) ; return txt ; } +inline ::string ensure_nl (::string const& txt) { return ensure_nl (::copy(txt)) ; } +inline ::string ensure_no_nl(::string const& txt) { return ensure_no_nl(::copy(txt)) ; } + +template void _append_to_string( ::string& dst , T&& x ) { dst += to_string(::forward(x)) ; } +inline void _append_to_string( ::string& dst , ::string const& s ) { dst += s ; } // fast path +inline void _append_to_string( ::string& dst , const char* s ) { dst += s ; } // . +inline void _append_to_string( ::string& dst , char c ) { dst += c ; } // . template void append_to_string( ::string& dst , A&&... args ) { [[maybe_unused]] bool _[] = { false , (_append_to_string(dst,::forward(args)),false)... } ; } @@ -347,8 +347,8 @@ template void append_line_to_string( ::string& dst , A&&... args ) { append_to_string(dst,::forward(args)...) ; } -template static inline ::string indent( ::string const& s , size_t i=1 ) { - ::string res ; res.reserve(s.size()+N*(s.size()>>4)) ; // anticipate lines of size 16, this is a reasonable pessimistic guess (as overflow is expensive) +template ::string indent( ::string const& s , size_t i=1 ) { + ::string res ; res.reserve(s.size()+N*(s.size()>>4)) ; // anticipate lines of size 16, this is a reasonable pessimistic guess (as overflow is expensive) bool sol = true ; for( char c : s ) { if (sol) for( size_t k=0 ; k static inline ::string indent( ::string const& return res ; } -static inline bool is_identifier(::string const& s) { +inline bool is_identifier(::string const& s) { /**/ if (!s ) return false ; /**/ if (!( ::isalpha(s[0]) || s[0]=='_' )) return false ; for( char c : s ) if (!( ::isalnum(c ) || c =='_' )) return false ; /**/ return true ; } -static inline ::string strip(::string const& txt) { +inline ::string strip(::string const& txt) { size_t start = 0 ; size_t end = txt.size() ; while ( start static inline I decode_int(const char* p) { +template<::integral I> I decode_int(const char* p) { I r = 0 ; for( uint8_t i=0 ; i static inline void encode_int( char* p , I x ) { - for( uint8_t i=0 ; i>(i*8)) ; // little endian +template<::integral I> void encode_int( char* p , I x ) { + for( uint8_t i=0 ; i>(i*8)) ; // little endian } ::string glb_subst( ::string&& txt , ::string const& sub , ::string const& repl ) ; @@ -432,9 +432,9 @@ template< ::integral I> ::string to_string_with_units (I x) extern thread_local char t_thread_key ; -static bool/*done*/ kill_self ( int sig ) ; -/**/ void set_sig_handler( int sig , void (*handler)(int) ) ; -/**/ void write_backtrace( ::ostream& os , int hide_cnt ) ; +bool/*done*/ kill_self ( int sig ) ; +void set_sig_handler( int sig , void (*handler)(int) ) ; +void write_backtrace( ::ostream& os , int hide_cnt ) ; template [[noreturn]] void crash( int hide_cnt , int sig , A const&... args ) { static bool busy = false ; @@ -457,7 +457,7 @@ template [[noreturn]] void crash( int hide_cnt , int sig , A const&. ::abort() ; } -[[noreturn]] static inline void unreachable() { +[[noreturn]] inline void unreachable() { #ifdef __has_builtin #if __has_builtin(__builtin_unreachable) __builtin_unreachable() ; @@ -469,7 +469,7 @@ template [[noreturn]] void crash( int hide_cnt , int sig , A const&. #endif } -template [[noreturn]] static inline void fail( A const&... args [[maybe_unused]] ) { +template [[noreturn]] void fail( A const&... args [[maybe_unused]] ) { #ifndef NDEBUG crash( 1 , SIGABRT , "fail @" , args... ) ; #else @@ -477,10 +477,10 @@ template [[noreturn]] static inline void fail( A const&... args [[ma #endif } -template static inline constexpr void throw_if ( bool cond , A const&... args ) { if ( cond) throw to_string(args...) ; } -template static inline constexpr void throw_unless( bool cond , A const&... args ) { if (!cond) throw to_string(args...) ; } +template constexpr void throw_if ( bool cond , A const&... args ) { if ( cond) throw to_string(args...) ; } +template constexpr void throw_unless( bool cond , A const&... args ) { if (!cond) throw to_string(args...) ; } -template static inline constexpr void swear( bool cond , A const&... args [[maybe_unused]] ) { +template constexpr void swear( bool cond , A const&... args [[maybe_unused]] ) { #ifndef NDEBUG if (!cond) crash( 1 , SIGABRT , "assertion violation @" , args... ) ; #else @@ -488,11 +488,11 @@ template static inline constexpr void swear( bool cond , A const&... #endif } -template [[noreturn]] static inline void fail_prod( A const&... args ) { +template [[noreturn]] void fail_prod( A const&... args ) { crash( 1 , SIGABRT , "fail @ " , args... ) ; } -template static inline constexpr void swear_prod( bool cond , A const&... args ) { +template constexpr void swear_prod( bool cond , A const&... args ) { if (!cond) crash( 1 , SIGABRT , "assertion violation @" , args... ) ; } @@ -505,13 +505,15 @@ template static inline constexpr void swear_prod( bool cond , A cons #define DF default : FAIL() ; // for use at end of switch statements -static inline bool/*done*/ kill_process( pid_t pid , int sig , bool as_group=false ) { - swear_prod(pid>1,"killing process ",pid) ; // ensure no system wide catastrophe ! - bool proc_killed = ::kill( pid,sig)==0 ; // kill process before process group as maybe, setpgid(0,0) has not been called in the child yet - bool group_killed = as_group && ::kill(-pid,sig)==0 ; // kill group if asked so, whether proc was killed or not +inline bool/*done*/ kill_process( pid_t pid , int sig , bool as_group=false ) { + swear_prod(pid>1,"killing process ",pid) ; // ensure no system wide catastrophe ! + bool proc_killed = ::kill( pid,sig)==0 ; // kill process before process group as maybe, setpgid(0,0) has not been called in the child yet + bool group_killed = as_group && ::kill(-pid,sig)==0 ; // kill group if asked so, whether proc was killed or not return proc_killed || group_killed ; } -static inline bool/*done*/ kill_self(int sig) { return kill_process(::getpid(),sig) ; } // raise kills the thread, not the process +inline bool/*done*/ kill_self(int sig) { // raise kills the thread, not the process + return kill_process(::getpid(),sig) ; +} // // vector_view @@ -597,7 +599,7 @@ template< class V> using vmap_view_c_s = vmap_view_c <::string,V > ; // math // -static constexpr inline uint8_t n_bits(size_t n) { return sizeof(size_t)*8-::countl_zero(n-1) ; } // number of bits to store n states +constexpr inline uint8_t n_bits(size_t n) { return sizeof(size_t)*8-::countl_zero(n-1) ; } // number of bits to store n states #define SCI static constexpr inline template<::integral T=size_t> SCI T bit_msk ( bool x , uint8_t b ) { return T(x)< SCI T bits ( T x , uint8_t w , uint8_t ls template<::integral T > SCI T bits ( T x , uint8_t w , uint8_t lsb , T v ) { return (x&~bits_msk(w,lsb)) | bits_msk(v,w,lsb) ; } // set bits #undef SCI -template static constexpr inline N round_down(N n,D d) { return n - n%d ; } -template static constexpr inline N div_down (N n,D d) { return n/d ; } -template static constexpr inline N round_up (N n,D d) { return round_down(n+d-1,d) ; } -template static constexpr inline N div_up (N n,D d) { return div_down (n+d-1,d) ; } +template constexpr N round_down(N n,D d) { return n - n%d ; } +template constexpr N div_down (N n,D d) { return n/d ; } +template constexpr N round_up (N n,D d) { return round_down(n+d-1,d) ; } +template constexpr N div_up (N n,D d) { return div_down (n+d-1,d) ; } static constexpr double Infinity = ::numeric_limits::infinity () ; static constexpr double Nan = ::numeric_limits::quiet_NaN() ; @@ -628,7 +630,7 @@ static constexpr double Nan = ::numeric_limits::quiet_NaN() ; namespace std { - #define OP(...) static inline ::ostream& operator<<( ::ostream& os , __VA_ARGS__ ) + #define OP(...) inline ::ostream& operator<<( ::ostream& os , __VA_ARGS__ ) template OP( T const a[N] ) { os <<'[' ; const char* sep="" ; for( T const& x : a ) { os< OP( array const& a ) { os <<'[' ; const char* sep="" ; for( T const& x : a ) { os< OP( vector const& v ) { os <<'[' ; const char* sep="" ; for( T const& x : v ) { os< OP( pair const& p ) { return os <<'('<< p.first <<','<< p.second <<')' ; } #undef OP - static inline ::ostream& operator<<( ::ostream& os , uint8_t const i ) { return os< static constexpr ::array _enum_split0(const char* comma_sep) { +template constexpr ::array _enum_split0(const char* comma_sep) { ::array res {} ; char* q = res.data() ; bool sep = true ; @@ -667,7 +669,7 @@ template static constexpr ::array _enum_split0(const char* c return res ; } -template static constexpr ::array _enum_snake0(::array const& camel0) { // at worst, snake inserts a _ before all chars, doubling the size +template constexpr ::array _enum_snake0(::array const& camel0) { // at worst, snake inserts a _ before all chars, doubling the size ::array res {}/*constexpr*/ ; char* q = res.data() ; bool first = true ; @@ -679,7 +681,7 @@ template static constexpr ::array _enum_snake0(::array static constexpr ::array _enum_mk_tab(::array const& vals) { +template constexpr ::array _enum_mk_tab(::array const& vals) { ::array res {}/*constexpr*/ ; const char* item = vals.data() ; for( size_t i=0 ; i static constexpr ::array _enum_mk // but then, clang requires the specialization to be static as well while gcc forbids it // using an anonymous namespace is ok with both and provides the same functionality namespace { - template constexpr bool IsStdEnum = false ; // unless specialized + template constexpr bool IsStdEnum = false ; // unless specialized } template concept StdEnum = IsStdEnum ; namespace { @@ -712,7 +714,7 @@ template static constexpr ::array<::string_view,N > template static constexpr size_t NBits = sizeof(T)*8 ; template static constexpr size_t NBits = n_bits(N) ; -template static inline ::ostream& operator<<( ::ostream& os , E e ) { +template ::ostream& operator<<( ::ostream& os , E e ) { if (e) return os << camel(e) ; else return os << "N+"<<(+e-N) ; } @@ -724,7 +726,7 @@ template ::string snake_str (E e) { return ::string(EnumSnakes const char* camel_cstr(E e) { return EnumCamels[+e].data() ; } // string_view's in this table have a terminating null template const char* snake_cstr(E e) { return EnumSnakes[+e].data() ; } // . -template static inline ::umap_s _mk_enum_tab() { +template ::umap_s _mk_enum_tab() { ::umap_s res ; for( E e : All ) { res[camel_str(e)] = e ; @@ -732,18 +734,18 @@ template static inline ::umap_s _mk_enum_tab() { } return res ; } -template static inline ::pair _mk_enum(::string const& x) { +template ::pair _mk_enum(::string const& x) { static ::umap_s const s_tab = _mk_enum_tab() ; auto it = s_tab.find(x) ; if (it==s_tab.end()) return {{} ,false/*ok*/} ; else return {it->second,true /*ok*/} ; } -template static inline bool can_mk_enum(::string const& x) { +template bool can_mk_enum(::string const& x) { return _mk_enum(x).second ; } -template static inline E mk_enum(::string const& x) { +template E mk_enum(::string const& x) { ::pair res = _mk_enum(x) ; if (!res.second) throw to_string("cannot make enum ",EnumName," from ",x) ; return res.first ; @@ -768,26 +770,26 @@ template static inline E mk_enum(::string const& x) { template using EnumUint = underlying_type_t ; template using EnumInt = ::make_signed_t> ; -template static inline constexpr EnumUint operator+(E e) { return EnumUint(e) ; } -template static inline constexpr bool operator!(E e) { return !+e ; } +template constexpr EnumUint operator+(E e) { return EnumUint(e) ; } +template constexpr bool operator!(E e) { return !+e ; } // -template static inline constexpr E operator+ (E e,EnumInt i) { e = E(+e+ i) ; return e ; } -template static inline constexpr E& operator+=(E& e,EnumInt i) { e = E(+e+ i) ; return e ; } -template static inline constexpr E operator- (E e,EnumInt i) { e = E(+e- i) ; return e ; } -template static inline constexpr EnumInt operator- (E e,E o) { EnumInt d ; d = +e-+o ; return d ; } -template static inline constexpr E& operator-=(E& e,EnumInt i) { e = E(+e- i) ; return e ; } -template static inline constexpr E operator++(E& e ) { e = E(+e+ 1) ; return e ; } -template static inline constexpr E operator++(E& e,int ) { E e_ = e ; e = E(+e+ 1) ; return e_ ; } -template static inline constexpr E operator--(E& e ) { e = E(+e- 1) ; return e ; } -template static inline constexpr E operator--(E& e,int ) { E e_ = e ; e = E(+e- 1) ; return e_ ; } +template constexpr E operator+ (E e,EnumInt i) { e = E(+e+ i) ; return e ; } +template constexpr E& operator+=(E& e,EnumInt i) { e = E(+e+ i) ; return e ; } +template constexpr E operator- (E e,EnumInt i) { e = E(+e- i) ; return e ; } +template constexpr EnumInt operator- (E e,E o) { EnumInt d ; d = +e-+o ; return d ; } +template constexpr E& operator-=(E& e,EnumInt i) { e = E(+e- i) ; return e ; } +template constexpr E operator++(E& e ) { e = E(+e+ 1) ; return e ; } +template constexpr E operator++(E& e,int ) { E e_ = e ; e = E(+e+ 1) ; return e_ ; } +template constexpr E operator--(E& e ) { e = E(+e- 1) ; return e ; } +template constexpr E operator--(E& e,int ) { E e_ = e ; e = E(+e- 1) ; return e_ ; } // -template static inline constexpr E operator& (E e,E o) { return ::min(e,o) ; } -template static inline constexpr E operator| (E e,E o) { return ::max(e,o) ; } -template static inline constexpr E& operator&=(E& e,E o) { e = e&o ; return e ; } -template static inline constexpr E& operator|=(E& e,E o) { e = e|o ; return e ; } +template constexpr E operator& (E e,E o) { return ::min(e,o) ; } +template constexpr E operator| (E e,E o) { return ::max(e,o) ; } +template constexpr E& operator&=(E& e,E o) { e = e&o ; return e ; } +template constexpr E& operator|=(E& e,E o) { e = e|o ; return e ; } // -template static inline E decode_enum( const char* p ) { return E(decode_int>(p)) ; } -template static inline void encode_enum( char* p , E e ) { encode_int(p,+e) ; } +template E decode_enum( const char* p ) { return E(decode_int>(p)) ; } +template void encode_enum( char* p , E e ) { encode_int(p,+e) ; } template struct BitMap { template friend ::ostream& operator<<( ::ostream& , BitMap const ) ; @@ -828,9 +830,9 @@ private : Val _val = 0 ; } ; // -template static inline constexpr BitMap operator~(E e) { return ~BitMap(e) ; } +template constexpr BitMap operator~(E e) { return ~BitMap(e) ; } -template static inline BitMap mk_bitmap( ::string const& x , char sep=',' ) { +template BitMap mk_bitmap( ::string const& x , char sep=',' ) { BitMap res ; for( ::string const& s : split(x,sep) ) res |= mk_enum(s) ; return res ; @@ -848,8 +850,8 @@ template struct EnumIterator { E val ; } ; -template static inline EnumIterator begin(E ) { return EnumIterator(E(0)) ; } -template static inline EnumIterator end (E e) { return EnumIterator(e ) ; } +template EnumIterator begin(E ) { return EnumIterator(E(0)) ; } +template EnumIterator end (E e) { return EnumIterator(e ) ; } template ::ostream& operator<<( ::ostream& os , BitMap const bm ) { os <<'(' ; @@ -877,35 +879,35 @@ ENUM(Bool3 static constexpr Bool3 No = Bool3::No ; static constexpr Bool3 Maybe = Bool3::Maybe ; static constexpr Bool3 Yes = Bool3::Yes ; -static inline Bool3 operator~ ( Bool3 b ) { return Bool3(+Yes-+b) ; } -static inline Bool3 operator! ( Bool3 b ) { return ~b ; } -static inline Bool3 operator| ( Bool3 b1 , bool b2 ) { return b2 ? Yes : b1 ; } -static inline Bool3 operator& ( Bool3 b1 , bool b2 ) { return !b2 ? No : b1 ; } -static inline Bool3 operator| ( bool b1 , Bool3 b2 ) { return b1 ? Yes : b2 ; } -static inline Bool3 operator& ( bool b1 , Bool3 b2 ) { return !b1 ? No : b2 ; } -static inline Bool3& operator|= ( Bool3& b1 , bool b2 ) { b1 = b1 | b2 ; return b1 ; } -static inline Bool3& operator&= ( Bool3& b1 , bool b2 ) { b1 = b1 & b2 ; return b1 ; } -static inline Bool3 common ( Bool3 b1 , Bool3 b2 ) { return b1==Yes ? (b2==Yes?Yes:Maybe) : b1==No ? ( b2==No?No:Maybe) : Maybe ; } -static inline Bool3 common ( Bool3 b1 , bool b2 ) { return b2 ? (b1==Yes?Yes:Maybe) : ( b1==No?No:Maybe) ; } -static inline Bool3 common ( bool b1 , Bool3 b2 ) { return b1 ? (b2==Yes?Yes:Maybe) : ( b2==No?No:Maybe) ; } -static inline Bool3 common ( bool b1 , bool b2 ) { return b1 ? (b2 ?Yes:Maybe) : (!b2 ?No:Maybe) ; } +inline Bool3 operator~ ( Bool3 b ) { return Bool3(+Yes-+b) ; } +inline Bool3 operator! ( Bool3 b ) { return ~b ; } +inline Bool3 operator| ( Bool3 b1 , bool b2 ) { return b2 ? Yes : b1 ; } +inline Bool3 operator& ( Bool3 b1 , bool b2 ) { return !b2 ? No : b1 ; } +inline Bool3 operator| ( bool b1 , Bool3 b2 ) { return b1 ? Yes : b2 ; } +inline Bool3 operator& ( bool b1 , Bool3 b2 ) { return !b1 ? No : b2 ; } +inline Bool3& operator|= ( Bool3& b1 , bool b2 ) { b1 = b1 | b2 ; return b1 ; } +inline Bool3& operator&= ( Bool3& b1 , bool b2 ) { b1 = b1 & b2 ; return b1 ; } +inline Bool3 common ( Bool3 b1 , Bool3 b2 ) { return b1==Yes ? (b2==Yes?Yes:Maybe) : b1==No ? ( b2==No?No:Maybe) : Maybe ; } +inline Bool3 common ( Bool3 b1 , bool b2 ) { return b2 ? (b1==Yes?Yes:Maybe) : ( b1==No?No:Maybe) ; } +inline Bool3 common ( bool b1 , Bool3 b2 ) { return b1 ? (b2==Yes?Yes:Maybe) : ( b2==No?No:Maybe) ; } +inline Bool3 common ( bool b1 , bool b2 ) { return b1 ? (b2 ?Yes:Maybe) : (!b2 ?No:Maybe) ; } // // miscellaneous // -static inline bool has_env(::string const& name) { +inline bool has_env(::string const& name) { return ::getenv(name.c_str()) ; } -static inline ::string get_env( ::string const& name , ::string const& dflt={} ) { +inline ::string get_env( ::string const& name , ::string const& dflt={} ) { if ( const char* c_path = ::getenv(name.c_str()) ) return c_path ; else return dflt ; } -static inline void set_env( ::string const& name , ::string const& val ) { +inline void set_env( ::string const& name , ::string const& val ) { int rc = ::setenv( name.c_str() , val.c_str() , true ) ; swear_prod(rc==0,"cannot setenv ",name," to ",val) ; } -static inline void del_env(::string const& name) { +inline void del_env(::string const& name) { int rc = ::unsetenv(name.c_str()) ; swear_prod(rc==0,"cannot unsetenv ",name) ; } @@ -952,9 +954,9 @@ private : Mutex _mutex ; } ; -static inline void fence() { ::atomic_signal_fence(::memory_order_acq_rel) ; } // ensure execution order in case of crash to guaranty disk integrity +inline void fence() { ::atomic_signal_fence(::memory_order_acq_rel) ; } // ensure execution order in case of crash to guaranty disk integrity -template static inline T clone(T const& x) { return x ; } // simply clone a value +template T clone(T const& x) { return x ; } // simply clone a value template struct Save { Save( T& ref , T const& val ) : saved{ref},_ref{ref} { _ref = val ; if (Fence) fence() ; } // save and init, ensure sequentiality if asked to do so @@ -994,7 +996,7 @@ template [[noreturn]] void exit( Rc rc , A const&... args ) { // string // -static constexpr bool _can_be_delimiter(char c) { // ensure delimiter does not clash with encoding +inline constexpr bool _can_be_delimiter(char c) { // ensure delimiter does not clash with encoding if ( c=='\\' ) return false ; if ( 'a'<=c && c<='z' ) return false ; if ( '0'<=c && c<='9' ) return false ; @@ -1052,7 +1054,7 @@ template ::pair_s parse_printable( ::string c return {res,p-start} ; } -static constexpr inline int _unit_val(char u) { +constexpr inline int _unit_val(char u) { switch (u) { case 'E' : return 60 ; break ; case 'P' : return 50 ; break ; diff --git a/unit_tests/target.py b/unit_tests/target.py index 4a67b981..23b98b34 100644 --- a/unit_tests/target.py +++ b/unit_tests/target.py @@ -28,15 +28,16 @@ class Base(Rule) : class ShCpy(Base) : targets = { 'DST' : '{File}.sh.{YesNo}.cpy' } cmd = ''' - [ {YesNo} = y ] && ltarget {DST} ; cat>{DST} - ltarget -s side.sh ; echo side > side.sh + [ {YesNo} = y ] && ( ltarget {DST} ; cat>{DST} ) + ltarget -s side.sh ; echo side > side.sh ''' class PyCpy(Base) : targets = { 'DST' : '{File}.py.{YesNo}.cpy' } def cmd() : - if YesNo=='y' : lmake.target(DST) - open(DST,'w').write(sys.stdin.read()) + if YesNo=='y' : + lmake.target(DST) + open(DST,'w').write(sys.stdin.read()) lmake.target('side.py',source_ok=True) print('side',file=open('side.py','w'))