// -*- 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 using namespace std::chrono_literals; 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; } const std::string ctor_exe{"./ctor"}; const std::string obj_ext{".o"}; void copy_config(std::string cfg) { std::cout << "** ctor_files/ctor.cc." + cfg + "\n"; std::filesystem::copy("ctor_files/ctor.cc." + cfg, "ctor.cc", std::filesystem::copy_options::overwrite_existing); if(std::filesystem::exists(ctor_exe)) { auto ctor_exe_time = std::filesystem::last_write_time(ctor_exe); std::filesystem::last_write_time("ctor.cc", ctor_exe_time + 1s); } } int main() { 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"); ////////////////////////////////////////////////////////////////////////////// copy_config("base"); // Compile bootstrap binary std::vector args = {"-pthread", "-std=c++20", "-L", CTORDIR, "-lctor", "-I", "../../src", "ctor.cc", "-o", ctor_exe}; // 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_exe); args = {"configure", "--ctor-includedir", "../../src", "--ctor-libdir=" + CTORDIR, "--build-dir=" + BUILDDIR}; ret = execute(settings, ctor_exe, args); if(ret != 0) { return fail(ret); } // ctor should be rebuilt at this point, so binary should have changed auto ctor_bin2 = readFile(ctor_exe); 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" + obj_ext)) { return fail(); } ctor_bin = readFile(ctor_exe); // Run normally to build project args = {"-v"}; ret = execute(settings, ctor_exe, args); if(ret != 0) { return fail(ret); } // Compiled object should now exist if(!std::filesystem::exists(BUILDDIR + "/hello-hello_cc" + obj_ext)) { return fail(); } // ctor should not have been rebuilt, so binary should be the same ctor_bin2 = readFile(ctor_exe); if(ctor_bin != ctor_bin2) { return fail(); } std::this_thread::sleep_for(1100ms); auto time = std::filesystem::last_write_time(BUILDDIR + "/hello-hello_cc" + obj_ext); 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_exe, args); if(ret != 0) { return fail(ret); } // Object file should have been recompiled auto time2 = std::filesystem::last_write_time(BUILDDIR + "/hello-hello_cc" + obj_ext); if(time == time2) { return fail(); } } ////////////////////////////////////////////////////////////////////////////// { // Replace -DFOO with -DBAR in foo external.cxxflags copy_config("bar"); auto configuration_cc_bin = readFile("configuration.cc"); auto ctor_bin = readFile(ctor_exe); auto time = std::filesystem::last_write_time(BUILDDIR + "/hello-hello_cc" + obj_ext); std::this_thread::sleep_for(1100ms); // Run normally to reconfigure, rebuild ctor and rebuild hello.cc args = {"-v"}; ret = execute(settings, ctor_exe, args); if(ret != 0) { return fail(ret); } auto time2 = std::filesystem::last_write_time(BUILDDIR + "/hello-hello_cc" + obj_ext); if(time == time2) { return fail(); } auto configuration_cc_bin2 = readFile("configuration.cc"); if(configuration_cc_bin == configuration_cc_bin2) { return fail(); } auto ctor_bin2 = readFile(ctor_exe); if(ctor_bin == ctor_bin2) { return fail(); } } ////////////////////////////////////////////////////////////////////////////// { copy_config("multi"); auto configuration_cc_bin = readFile("configuration.cc"); auto ctor_bin = readFile(ctor_exe); auto time = std::filesystem::last_write_time(BUILDDIR + "/hello-hello_cc" + obj_ext); std::this_thread::sleep_for(1100ms); // Run normally to reconfigure, rebuild ctor and rebuild hello.cc args = {"-v"}; ret = execute(settings, ctor_exe, args); if(ret != 0) { return fail(ret); } auto time2 = std::filesystem::last_write_time(BUILDDIR + "/hello-hello_cc" + obj_ext); if(time == time2) { return fail(); } auto configuration_cc_bin2 = readFile("configuration.cc"); if(configuration_cc_bin == configuration_cc_bin2) { return fail(); } auto ctor_bin2 = readFile(ctor_exe); if(ctor_bin == ctor_bin2) { return fail(); } // now touching foobar.h, should retrigger re-configuration time = std::filesystem::last_write_time(ctor_exe); std::filesystem::last_write_time("foobar.h", time + 1s); std::this_thread::sleep_for(1100ms); // Run normally to reconfigure, rebuild ctor and rebuild hello.cc args = {"-v"}; ret = execute(settings, ctor_exe, args); if(ret != 0) { return fail(ret); } time2 = std::filesystem::last_write_time(ctor_exe); if(time == time2) { return fail(); } } ////////////////////////////////////////////////////////////////////////////// { copy_config("generated"); std::filesystem::remove(BUILDDIR + "/world.cc"); std::filesystem::remove(BUILDDIR + "/foo.cc"); auto configuration_cc_bin = readFile("configuration.cc"); auto ctor_bin = readFile(ctor_exe); std::this_thread::sleep_for(1100ms); // Run normally to reconfigure, rebuild ctor and build world.cc args = {"-v", "world"}; ret = execute(settings, ctor_exe, args); if(ret != 0) { return fail(ret); } auto configuration_cc_bin2 = readFile("configuration.cc"); if(configuration_cc_bin == configuration_cc_bin2) { return fail(); } auto ctor_bin2 = readFile(ctor_exe); 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" + obj_ext); 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_exe, 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" + obj_ext); if(time_w == time_w2) { return fail(); } if(time_wo == time_wo2) { return fail(); } } return 0; }