#include "../../src/util.cc" #include "../../src/pointerlist.cc" #include "../../src/execute.cc" #include #include #include #include #include #include //function fail //{ // echo "*** Failure at line $1" // exit 1 //} // //function ctor //{ // echo "*** Running: ./ctor $*" // ./ctor $* //} std::vector tokenize(const std::string& str) { std::vector tokens; std::stringstream ss(str); std::string token; while(getline(ss, token, ' ')) { tokens.push_back(token); } return tokens; } int fail(int value = 1, const std::source_location location = std::source_location::current()) { std::cout << "*** Failure at line " << location.line() << '\n'; return value; } int main() { using namespace std::chrono_literals; ctor::settings settings{}; settings.verbose = 2; auto paths = get_paths(); //: ${CXX:=g++} std::string CXX = "g++"; get_env("CXX", CXX); //: ${CTORDIR:=../../build} std::string CTORDIR = "../../build"; get_env("CTORDIR", CTORDIR); //: ${BUILDDIR:=build} std::string BUILDDIR = "build"; get_env("BUILDDIR", BUILDDIR); std::string CXXFLAGS; get_env("CXXFLAGS", CXXFLAGS); std::string LDFLAGS; get_env("LDFLAGS", LDFLAGS); // //CXX=$(which $CXX) auto cxx_prog = locate(CXX, paths); // // //STAT_FORMAT="-c %Y" //if [[ "$OSTYPE" == "darwin"* ]]; then // # Mac OSX // STAT_FORMAT="-f %B" //fi // //# Wipe the board //rm -Rf ${BUILDDIR} std::filesystem::remove_all(BUILDDIR); //rm -f configuration.cc std::filesystem::remove("configuration.cc"); std::filesystem::remove("config.h"); //rm -f ctor std::filesystem::remove("ctor"); // //echo "** ctor_files/ctor.cc.base" std::cout << "** ctor_files/ctor.cc.base\n"; //cp ctor_files/ctor.cc.base ctor.cc std::filesystem::copy("ctor_files/ctor.cc.base", "ctor.cc", std::filesystem::copy_options::overwrite_existing); // //# Compile bootstrap binary //$CXX -pthread $LDFLAGS $CXXFLAGS -std=c++20 -L${CTORDIR} -lctor -I../../src ctor.cc -o ctor || fail ${LINENO} std::vector args = {"-pthread", "-std=c++20", "-L", CTORDIR, "-lctor", "-I", "../../src", "ctor.cc", "-o", "ctor"}; // TODO: if(!CXXFLAGS.empty()) { auto tokens = tokenize(CXXFLAGS); for(const auto& token : tokens) { args.push_back(token); } } if(!LDFLAGS.empty()) { auto tokens = tokenize(LDFLAGS); for(const auto& token : tokens) { args.push_back(token); } } auto ret = execute(settings, cxx_prog, args); if(ret != 0) { return fail(ret); } // //# No build files should have been created yet //[ -d ${BUILDDIR} ] && fail ${LINENO} if(std::filesystem::exists(BUILDDIR)) { return fail(); } // //# capture md5 sum of ctor binary before configure is called //MD5=`md5sum ctor` auto ctor_bin = readFile("ctor"); //ctor configure --ctor-includedir ../../src --ctor-libdir=${CTORDIR} --build-dir=${BUILDDIR} args = {"configure", "--ctor-includedir", "../../src", "--ctor-libdir="+CTORDIR, "--build-dir="+BUILDDIR}; ret = execute(settings, "./ctor", args); if(ret != 0) { return fail(ret); } // //# ctor should be rebuilt at this point, so md5 sum should have changed //(echo $MD5 | md5sum --status -c) && fail ${LINENO} auto ctor_bin2 = readFile("ctor"); if(ctor_bin == ctor_bin2) { return fail(); } // //# configuration.cc should have been generated now //[ ! -f configuration.cc ] && fail ${LINENO} if(!std::filesystem::exists("configuration.cc")) { return fail(); } if(!std::filesystem::exists("config.h")) { return fail(); } // //# Shouldn't compile anything yet - only configure //[ -f ${BUILDDIR}/hello-hello_cc.o ] && fail ${LINENO} if(std::filesystem::exists(BUILDDIR+"/hello-hello_cc.o")) { return fail(); } // //MD5=`md5sum ctor` ctor_bin = readFile("ctor"); // //# Run normally to build project //ctor -v args = {"-v"}; ret = execute(settings, "./ctor", args); if(ret != 0) { return fail(ret); } // //# Compiled object should now exist //[ ! -f ${BUILDDIR}/hello-hello_cc.o ] && fail ${LINENO} if(!std::filesystem::exists(BUILDDIR+"/hello-hello_cc.o")) { return fail(); } // //# ctor should not have been rebuilt, so md5 sum should be the same //(echo $MD5 | md5sum --status -c) || fail ${LINENO} ctor_bin2 = readFile("ctor"); if(ctor_bin != ctor_bin2) { return fail(); } std::this_thread::sleep_for(1100ms); // //MOD1=`stat $STAT_FORMAT ${BUILDDIR}/hello-hello_cc.o` auto time = std::filesystem::last_write_time(BUILDDIR+"/hello-hello_cc.o"); //touch hello.cc std::filesystem::last_write_time("hello.cc", time + 1s); //sleep 1.1 std::this_thread::sleep_for(1100ms); // //# Run normally to rebuild hello.cc //ctor -v args = {"-v"}; ret = execute(settings, "./ctor", args); if(ret != 0) { return fail(ret); } // //# Object file should have been recompiled //MOD2=`stat $STAT_FORMAT ${BUILDDIR}/hello-hello_cc.o` auto time2 = std::filesystem::last_write_time(BUILDDIR+"/hello-hello_cc.o"); //[[ $MOD1 == $MOD2 ]] && fail ${LINENO} if(time == time2) { return fail(); } // //# Replace -DFOO with -DBAR in foo external.cxxflags //echo "** ctor_files/ctor.cc.bar" std::cout << "** ctor_files/ctor.cc.bar\n"; //cp ctor_files/ctor.cc.bar ctor.cc std::filesystem::copy("ctor_files/ctor.cc.bar", "ctor.cc", std::filesystem::copy_options::overwrite_existing); // //MD5C=`md5sum configuration.cc` auto configuration_cc_bin = readFile("configuration.cc"); //MD5=`md5sum ctor` ctor_bin = readFile("ctor"); //MOD1=`stat $STAT_FORMAT build/hello-hello_cc.o` time = std::filesystem::last_write_time(BUILDDIR+"/hello-hello_cc.o"); //sleep 1.1 std::this_thread::sleep_for(1100ms); // //# Run normally to reconfigure, rebuild ctor and rebuild hello.cc //ctor -v args = {"-v"}; ret = execute(settings, "./ctor", args); if(ret != 0) { return fail(ret); } // //MOD2=`stat $STAT_FORMAT ${BUILDDIR}/hello-hello_cc.o` time2 = std::filesystem::last_write_time(BUILDDIR+"/hello-hello_cc.o"); //[[ $MOD1 == $MOD2 ]] && fail ${LINENO} if(time == time2) { return fail(); } //(echo $MD5C | md5sum --status -c) && fail ${LINENO} auto configuration_cc_bin2 = readFile("configuration.cc"); if(configuration_cc_bin == configuration_cc_bin2) { return fail(); } //(echo $MD5 | md5sum --status -c) && fail ${LINENO} ctor_bin2 = readFile("ctor"); if(ctor_bin == ctor_bin2) { return fail(); } // //echo "** ctor_files/ctor.cc.multi" std::cout << "** ctor_files/ctor.cc.multi\n"; //cp ctor_files/ctor.cc.multi ctor.cc std::filesystem::copy("ctor_files/ctor.cc.multi", "ctor.cc", std::filesystem::copy_options::overwrite_existing); // //MD5C=`md5sum configuration.cc` configuration_cc_bin = readFile("configuration.cc"); //MD5=`md5sum ctor` ctor_bin = readFile("ctor"); //MOD1=`stat $STAT_FORMAT ${BUILDDIR}/hello-hello_cc.o` time = std::filesystem::last_write_time(BUILDDIR+"/hello-hello_cc.o"); //sleep 1.1 std::this_thread::sleep_for(1100ms); // //# Run normally to reconfigure, rebuild ctor and rebuild hello.cc //ctor -v args = {"-v"}; ret = execute(settings, "./ctor", args); if(ret != 0) { return fail(ret); } // //MOD2=`stat $STAT_FORMAT ${BUILDDIR}/hello-hello_cc.o` time2 = std::filesystem::last_write_time(BUILDDIR+"/hello-hello_cc.o"); //[[ $MOD1 == $MOD2 ]] && fail ${LINENO} if(time == time2) { return fail(); } //(echo $MD5C | md5sum --status -c) && fail ${LINENO} configuration_cc_bin2 = readFile("configuration.cc"); if(configuration_cc_bin == configuration_cc_bin2) { return fail(); } //(echo $MD5 | md5sum --status -c) && fail ${LINENO} ctor_bin2 = readFile("ctor"); if(ctor_bin == ctor_bin2) { return fail(); } // //# now touching foobar.h, should retrigger re-configuration //touch foobar.h time = std::filesystem::last_write_time("ctor"); std::filesystem::last_write_time("foobar.h", time + 1s); // //MOD1=`stat $STAT_FORMAT ctor` time = std::filesystem::last_write_time("ctor"); //sleep 1.1 std::this_thread::sleep_for(1100ms); // //# Run normally to reconfigure, rebuild ctor and rebuild hello.cc //ctor -v args = {"-v"}; ret = execute(settings, "./ctor", args); if(ret != 0) { return fail(ret); } // //MOD2=`stat $STAT_FORMAT ctor` time2 = std::filesystem::last_write_time("ctor"); //[[ $MOD1 == $MOD2 ]] && fail ${LINENO} if(time == time2) { return fail(); } // //echo "** ctor_files/ctor.cc.generated" std::cout << "** ctor_files/ctor.cc.generated\n"; //cp ctor_files/ctor.cc.generated ctor.cc std::filesystem::copy("ctor_files/ctor.cc.generated", "ctor.cc", std::filesystem::copy_options::overwrite_existing); //rm -f ${BUILDDIR}/world.cc ${BUILDDIR}/foo.cc std::filesystem::remove(BUILDDIR+"/world.cc"); std::filesystem::remove(BUILDDIR+"/foo.cc"); // //MD5C=`md5sum configuration.cc` configuration_cc_bin = readFile("configuration.cc"); //MD5=`md5sum ctor` ctor_bin = readFile("ctor"); //sleep 1.1 std::this_thread::sleep_for(1100ms); // //# Run normally to reconfigure, rebuild ctor and build world.cc //ctor -v world args = {"-v", "world"}; ret = execute(settings, "./ctor", args); if(ret != 0) { return fail(ret); } //(echo $MD5C | md5sum --status -c) && fail ${LINENO} configuration_cc_bin2 = readFile("configuration.cc"); if(configuration_cc_bin == configuration_cc_bin2) { return fail(); } //(echo $MD5 | md5sum --status -c) && fail ${LINENO} ctor_bin2 = readFile("ctor"); if(ctor_bin == ctor_bin2) { return fail(); } // //# foo.cc should not be generated at this point //ls ${BUILDDIR}/foo.cc //[[ $? != 0 ]] || fail ${LINENO} if(std::filesystem::exists(BUILDDIR+"/foo.cc")) { return fail(); } // //MOD1W=`stat $STAT_FORMAT ${BUILDDIR}/world.cc` auto time_w = std::filesystem::last_write_time(BUILDDIR+"/world.cc"); //MOD1=`stat $STAT_FORMAT ${BUILDDIR}/${BUILDDIR}/world-world_cc.o` auto time_wo = std::filesystem::last_write_time(BUILDDIR+"/"+BUILDDIR+"/world-world_cc.o"); // //sleep 1.1 std::this_thread::sleep_for(1100ms); // //# now touching hello.cc, should trigger regeneration of world.cc and rebuild //touch hello.cc std::filesystem::last_write_time("hello.cc", time_w + 1s); //ctor -v world args = {"-v", "world"}; ret = execute(settings, "./ctor", args); if(ret != 0) { return fail(ret); } // //MOD2W=`stat $STAT_FORMAT ${BUILDDIR}/world.cc` auto time_w2 = std::filesystem::last_write_time(BUILDDIR+"/world.cc"); //MOD2=`stat $STAT_FORMAT ${BUILDDIR}/${BUILDDIR}/world-world_cc.o` auto time_wo2 = std::filesystem::last_write_time(BUILDDIR+"/"+BUILDDIR+"/world-world_cc.o"); //[[ $MOD1W == $MOD2W ]] && fail ${LINENO} if(time_w == time_w2) { return fail(); } //[[ $MOD1 == $MOD2 ]] && fail ${LINENO} if(time_wo == time_wo2) { return fail(); } // //exit 0 return 0; }