// -*- c++ -*- // Distributed under the BSD 2-Clause License. // See accompanying file LICENSE for details. #include "../../src/util.cc" #include "../../src/pointerlist.cc" #include "../../src/execute.cc" #include #include #include #include #include #include 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(); std::string CXX = "g++"; get_env("CXX", CXX); std::string CTORDIR = "../../build"; get_env("CTORDIR", CTORDIR); std::string BUILDDIR = "build"; get_env("BUILDDIR", BUILDDIR); std::string CXXFLAGS; get_env("CXXFLAGS", CXXFLAGS); std::string LDFLAGS; get_env("LDFLAGS", LDFLAGS); auto cxx_prog = locate(CXX, paths); // Wipe the board std::filesystem::remove_all(BUILDDIR); std::filesystem::remove("configuration.cc"); std::filesystem::remove("config.h"); std::filesystem::remove("ctor"); ////////////////////////////////////////////////////////////////////////////// std::cout << "** ctor_files/ctor.cc.base\n"; std::filesystem::copy("ctor_files/ctor.cc.base", "ctor.cc", std::filesystem::copy_options::overwrite_existing); // Compile bootstrap binary std::vector args = {"-pthread", "-std=c++20", "-L", CTORDIR, "-lctor", "-I", "../../src", "ctor.cc", "-o", "ctor"}; // TODO: add support for quoted strings with spaces 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 if(std::filesystem::exists(BUILDDIR)) { return fail(); } // capture ctor binary before configure is called auto ctor_bin = readFile("ctor"); 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 binary should have changed auto ctor_bin2 = readFile("ctor"); if(ctor_bin == ctor_bin2) { return fail(); } // configuration.cc should have been generated now if(!std::filesystem::exists("configuration.cc")) { return fail(); } if(!std::filesystem::exists("config.h")) { return fail(); } // Shouldn't compile anything yet - only configure if(std::filesystem::exists(BUILDDIR+"/hello-hello_cc.o")) { return fail(); } ctor_bin = readFile("ctor"); // Run normally to build project args = {"-v"}; ret = execute(settings, "./ctor", args); if(ret != 0) { return fail(ret); } // Compiled object should now exist if(!std::filesystem::exists(BUILDDIR+"/hello-hello_cc.o")) { return fail(); } // ctor should not have been rebuilt, so binary should be the same ctor_bin2 = readFile("ctor"); if(ctor_bin != ctor_bin2) { return fail(); } std::this_thread::sleep_for(1100ms); auto time = std::filesystem::last_write_time(BUILDDIR+"/hello-hello_cc.o"); std::filesystem::last_write_time("hello.cc", time + 1s); std::this_thread::sleep_for(1100ms); // Run normally to rebuild hello.cc args = {"-v"}; ret = execute(settings, "./ctor", args); if(ret != 0) { return fail(ret); } // Object file should have been recompiled auto time2 = std::filesystem::last_write_time(BUILDDIR+"/hello-hello_cc.o"); if(time == time2) { return fail(); } ////////////////////////////////////////////////////////////////////////////// // Replace -DFOO with -DBAR in foo external.cxxflags std::cout << "** ctor_files/ctor.cc.bar\n"; std::filesystem::copy("ctor_files/ctor.cc.bar", "ctor.cc", std::filesystem::copy_options::overwrite_existing); auto configuration_cc_bin = readFile("configuration.cc"); ctor_bin = readFile("ctor"); time = std::filesystem::last_write_time(BUILDDIR+"/hello-hello_cc.o"); std::this_thread::sleep_for(1100ms); // Run normally to reconfigure, rebuild ctor and rebuild hello.cc args = {"-v"}; ret = execute(settings, "./ctor", args); if(ret != 0) { return fail(ret); } time2 = std::filesystem::last_write_time(BUILDDIR+"/hello-hello_cc.o"); if(time == time2) { return fail(); } auto configuration_cc_bin2 = readFile("configuration.cc"); if(configuration_cc_bin == configuration_cc_bin2) { return fail(); } ctor_bin2 = readFile("ctor"); if(ctor_bin == ctor_bin2) { return fail(); } ////////////////////////////////////////////////////////////////////////////// std::cout << "** ctor_files/ctor.cc.multi\n"; std::filesystem::copy("ctor_files/ctor.cc.multi", "ctor.cc", std::filesystem::copy_options::overwrite_existing); configuration_cc_bin = readFile("configuration.cc"); ctor_bin = readFile("ctor"); time = std::filesystem::last_write_time(BUILDDIR+"/hello-hello_cc.o"); std::this_thread::sleep_for(1100ms); // Run normally to reconfigure, rebuild ctor and rebuild hello.cc args = {"-v"}; ret = execute(settings, "./ctor", args); if(ret != 0) { return fail(ret); } time2 = std::filesystem::last_write_time(BUILDDIR+"/hello-hello_cc.o"); if(time == time2) { return fail(); } configuration_cc_bin2 = readFile("configuration.cc"); if(configuration_cc_bin == configuration_cc_bin2) { return fail(); } ctor_bin2 = readFile("ctor"); if(ctor_bin == ctor_bin2) { return fail(); } // now touching foobar.h, should retrigger re-configuration time = std::filesystem::last_write_time("ctor"); std::filesystem::last_write_time("foobar.h", time + 1s); time = std::filesystem::last_write_time("ctor"); std::this_thread::sleep_for(1100ms); // Run normally to reconfigure, rebuild ctor and rebuild hello.cc args = {"-v"}; ret = execute(settings, "./ctor", args); if(ret != 0) { return fail(ret); } time2 = std::filesystem::last_write_time("ctor"); if(time == time2) { return fail(); } ////////////////////////////////////////////////////////////////////////////// std::cout << "** ctor_files/ctor.cc.generated\n"; std::filesystem::copy("ctor_files/ctor.cc.generated", "ctor.cc", std::filesystem::copy_options::overwrite_existing); std::filesystem::remove(BUILDDIR+"/world.cc"); std::filesystem::remove(BUILDDIR+"/foo.cc"); configuration_cc_bin = readFile("configuration.cc"); ctor_bin = readFile("ctor"); std::this_thread::sleep_for(1100ms); // Run normally to reconfigure, rebuild ctor and build world.cc args = {"-v", "world"}; ret = execute(settings, "./ctor", args); if(ret != 0) { return fail(ret); } configuration_cc_bin2 = readFile("configuration.cc"); if(configuration_cc_bin == configuration_cc_bin2) { return fail(); } ctor_bin2 = readFile("ctor"); if(ctor_bin == ctor_bin2) { return fail(); } // foo.cc should not be generated at this point if(std::filesystem::exists(BUILDDIR+"/foo.cc")) { return fail(); } auto time_w = std::filesystem::last_write_time(BUILDDIR+"/world.cc"); auto time_wo = std::filesystem::last_write_time(BUILDDIR+"/"+BUILDDIR+"/world-world_cc.o"); std::this_thread::sleep_for(1100ms); // now touching hello.cc, should trigger regeneration of world.cc and rebuild std::filesystem::last_write_time("hello.cc", time_w + 1s); args = {"-v", "world"}; ret = execute(settings, "./ctor", args); if(ret != 0) { return fail(ret); } auto time_w2 = std::filesystem::last_write_time(BUILDDIR+"/world.cc"); auto time_wo2 = std::filesystem::last_write_time(BUILDDIR+"/"+BUILDDIR+"/world-world_cc.o"); if(time_w == time_w2) { return fail(); } if(time_wo == time_wo2) { return fail(); } return 0; }