The How

  • no depencencies other than the c++-20 compiler
  • the REG macro - automatic int a = registerFunction() wrapper.
  • std::filesystem for reading timestamps
  • execv, posix_spawn and friends for executing the compiler, linker and other tools
  • std::async for parallel compilation
  • std::thread::hardware_concurrency() for automatic -jn deduction
  • gcc -MMD for dependency tracking
  • configure target
    • cross-compilation and tool-chain control
  • trixy self-re-invoke (after re-compilation) when configuration files change.
    • tree of self-dependency weirdness:
      • main()
        2    if configure arg call configure(args), exit
        4    if reconfigure arg call reconfigure(args), exit
        1,3  other rebuildCheck
        1    build dirty project sources...
        
        configure(args)
          collect (relevant) env vars in map: A
        	collect (relevant) cli args in map: B
          call generateCache(A, B)
          then call rebuildCheck to force rebuild and then exit
        
        reconfigure(args)
          read A and B from (current) config cache and call generateCache(A, B) to
        	 generate a new one
          then call rebuildCheck to rebuild and then exit
        
        rebuildCheck()
          check if rebuild is needed (if any ctor.cc files or configuration.cc changed):
        	  rebuild
        		if !"only configuration.cc changed" re-run, with "reconfigure" argument
        
        generateCache(A, B)
          resolv tool-chain (compiler, linker, etc) and store in map: C
          run through externals and resolv them, store results in map: D
        	generate config cache .cc file with A, B, C and D
        Scenarios:
        
        1. No ctor deps changed (normal run)
           rebuild dirty project sources.
         OK
        
        2. a new configuration.cc has been generated (user called configure)
           regenerate cache
         * rebuild
         OK
        
        3. one or more ctor.cc files changed (run with args)
         * rebuild
           relaunch with 'reconfigure' with args (goto 4)
         OK
        
        4. run with reconfigure (with other args)
           "ignore" args but keep them for later
           regenerate cache
         * rebuild
           relauch with "other args" (goto 1)
         OK
  • independent target compilation (with dependency deduction)
  • clean target
  • bootstrapping (yes - libctor compiles itself)
  • check target, for unit test compilation and execution
  • compilation-database (json) for c-lion and others
  • currently working on:
    • external dependency flags with std::variant
      • manual dependency
      • automatic dependency deduction through searches
  • future work:
    • more external dependency variants:
      • pkg-config
      • conan
    • pre-/postbuild actions with conditions
    • globbing
    • custom target generation through external application (generators)
    • lambda functions as generators
    • custom compilation configuration control through configure target (like –with-X/–enable-Y in autotools)
    • install target with PREFIX and DESTDIR support
    • documentation :-)