diff options
| author | Bent Bisballe Nyeng <deva@aasimon.org> | 2025-12-27 15:08:07 +0100 |
|---|---|---|
| committer | Bent Bisballe Nyeng <deva@aasimon.org> | 2026-01-05 22:47:12 +0100 |
| commit | fa99825fa800f0faf4a6e6b1d639b261c7aa43c9 (patch) | |
| tree | 17945e16aa7f33c8aede1694c90a08b7cc05e0e1 | |
| parent | 5ac072c0f42bf3216d16f177c795e9324bf3c52b (diff) | |
Add many-to-one generator function type.develop
| -rw-r--r-- | src/ctor.h | 19 | ||||
| -rw-r--r-- | src/task.cc | 2 | ||||
| -rw-r--r-- | src/task.h | 2 | ||||
| -rw-r--r-- | src/task_fn.cc | 187 | ||||
| -rw-r--r-- | src/task_fn.h | 5 | ||||
| -rw-r--r-- | src/task_ld.cc | 5 | ||||
| -rw-r--r-- | src/task_ld.h | 1 | ||||
| -rw-r--r-- | src/tasks.cc | 16 | ||||
| -rw-r--r-- | test/generated_sources_test.cc | 55 | ||||
| -rw-r--r-- | test/suite/ctor_files/ctor.cc.generated | 39 | ||||
| -rw-r--r-- | test/suite/ctor_files/ctor.cc.generated2 | 86 | ||||
| -rw-r--r-- | test/suite/test.cc | 496 |
12 files changed, 630 insertions, 283 deletions
@@ -282,10 +282,17 @@ struct settings }; struct build_configuration; -using GeneratorCb = std::function<int(const std::string& input, - const std::string& output, - const build_configuration& config, - const ctor::settings& settings)>; +using GeneratorOneToOne = + std::function<int(const std::string& input, + const std::string& output, + const build_configuration& config, + const ctor::settings& settings)>; + +using GeneratorManyToOne = + std::function<int(const std::vector<std::string>& input, + const std::string& output, + const ctor::build_configuration& config, + const ctor::settings& settings)>; struct build_configuration { @@ -297,7 +304,9 @@ struct build_configuration std::vector<std::string> depends; // internal target dependencies ctor::flags flags; std::vector<std::string> externals; // externals used by this configuration - GeneratorCb function; + std::variant<std::monostate, + GeneratorOneToOne, + GeneratorManyToOne> function; }; using build_configurations = std::vector<build_configuration>; diff --git a/src/task.cc b/src/task.cc index 5484c23..17559bf 100644 --- a/src/task.cc +++ b/src/task.cc @@ -12,7 +12,7 @@ Task::Task(const ctor::build_configuration& config_, const ctor::settings& setti : config(config_) , output_system(config.system) , settings(settings_) - , sourceDir(std::move(sourceDir_)) + , sourceDir(sourceDir_) { } @@ -79,5 +79,5 @@ protected: ctor::language source_language{ctor::language::automatic}; ctor::output_system output_system{ctor::output_system::host}; const ctor::settings& settings; - std::string sourceDir; + std::filesystem::path sourceDir; }; diff --git a/src/task_fn.cc b/src/task_fn.cc index ebfdac6..69e36ac 100644 --- a/src/task_fn.cc +++ b/src/task_fn.cc @@ -11,46 +11,129 @@ #include "execute.h" #include "util.h" -TaskFn::TaskFn(const ctor::build_configuration& config_, const ctor::settings& settings_, - const std::string& sourceDir_, const ctor::source& source) +TaskFn::TaskFn(const ctor::build_configuration& config_, + const ctor::settings& settings_, + const std::string& sourceDir_, + const ctor::source& source) : Task(config_, settings_, sourceDir_) - , sourceFile(sourceDir_) , config(config_) , settings(settings_) { - sourceFile /= source.file; - - std::filesystem::create_directories(std::filesystem::path(settings.builddir) / sourceFile.parent_path()); - + std::filesystem::create_directories(std::filesystem::path(settings.builddir) / + sourceDir.parent_path()); target_type = config.type; source_language = source.language; - std::filesystem::path base = sourceFile.parent_path(); - if(source.output.empty()) + if(std::holds_alternative<ctor::GeneratorOneToOne>(config.function)) { - std::cerr << "Missing output file for functional target\n"; - exit(1); + if(source.source_type == ctor::source_type::generated) + { + sourceFile = std::filesystem::path(settings.builddir); + } + sourceFile /= sourceDir / source.file; + + std::filesystem::path base = sourceFile.parent_path(); + + if(source.output.empty()) + { + std::cerr << "Missing target/output file for functional target.\n"; + exit(1); + } + _targetFile = base / source.output; } + else if(std::holds_alternative<ctor::GeneratorManyToOne>(config.function)) + { + for(const auto& src : config.sources) + { + std::filesystem::path _src; + if(src.source_type == ctor::source_type::generated) + { + _src = std::filesystem::path(settings.builddir); + } + _src /= sourceDir / src.file; + sources.push_back(_src.string()); + } - _targetFile = base / source.output; + std::filesystem::path base = sourceDir; + if(config.target.empty()) + { + std::cerr << "Missing target file for functional target\n"; + exit(1); + } + _targetFile = base / config.target; + sourceListFile = targetFile().parent_path() / targetFile().filename(); + sourceListFile += ".sources"; + } } bool TaskFn::dirtyInner() { - if(!std::filesystem::exists(sourceFile)) + if(!std::filesystem::exists(targetFile())) { - //std::cout << "Missing source file: " << std::string(sourceFile) << "\n"; + //std::cout << "Missing targetFile\n"; return true; } - if(!std::filesystem::exists(targetFile())) + if(std::holds_alternative<ctor::GeneratorManyToOne>(config.function)) + { + if(!std::filesystem::exists(sourceListFile)) + { + //std::cout << "Missing sourceListFile\n"; + return true; + } + + { + auto lastSourceList = readFile(sourceListFile.string()); + if(sourceListString() != lastSourceList) + { + //std::cout << "The compiler sourceList changed\n"; + return true; + } + } + } + + std::filesystem::file_time_type last_changed{}; + bool missing{false}; + if(std::holds_alternative<ctor::GeneratorOneToOne>(config.function)) + { + if(!std::filesystem::exists(sourceFile)) + { + missing = true; + } + last_changed = std::filesystem::last_write_time(sourceFile); + } + else if(std::holds_alternative<ctor::GeneratorManyToOne>(config.function)) + { + bool first{true}; + for(const auto& source : sources) + { + if(!std::filesystem::exists(source)) + { + missing |= true; + } + else + { + if(first) + { + last_changed = std::filesystem::last_write_time(source); + } + else + { + last_changed = + std::max(last_changed, + std::filesystem::last_write_time(source)); + } + } + first = false; + } + } + + if(missing) { - //std::cout << "Missing targetFile\n"; return true; } - if(std::filesystem::last_write_time(sourceFile) > - std::filesystem::last_write_time(targetFile())) + if(last_changed > std::filesystem::last_write_time(targetFile())) { //std::cout << "The targetFile older than sourceFile\n"; return true; @@ -61,10 +144,11 @@ bool TaskFn::dirtyInner() int TaskFn::runInner() { - if(!std::filesystem::exists(sourceFile)) + if(std::holds_alternative<ctor::GeneratorManyToOne>(config.function)) { - std::cout << "Missing source file: " << sourceFile.string() << "\n"; - return 1; + // Write sourceList to file. + std::ofstream sourceListStream(sourceListFile.string()); + sourceListStream << sourceListString(); } if(settings.verbose >= 0) @@ -75,10 +159,27 @@ int TaskFn::runInner() std::cout << output << std::flush; } - auto res = config.function(sourceFile.string(), - targetFile().string(), - config, - settings); + int res{}; + if(std::holds_alternative<std::monostate>(config.function)) + { + } + else if(std::holds_alternative<ctor::GeneratorOneToOne>(config.function)) + { + auto func = std::get<ctor::GeneratorOneToOne>(config.function); + res = func(sourceFile.string(), + targetFile().string(), + config, + settings); + } + else if(std::holds_alternative<ctor::GeneratorManyToOne>(config.function)) + { + auto func = std::get<ctor::GeneratorManyToOne>(config.function); + res = func(sources, + targetFile().string(), + config, + settings); + } + if(res != 0) { std::filesystem::remove(targetFile()); @@ -95,12 +196,34 @@ int TaskFn::clean() std::filesystem::remove(targetFile()); } + if(std::holds_alternative<ctor::GeneratorManyToOne>(config.function)) + { + if(std::filesystem::exists(sourceListFile)) + { + std::cout << "Removing " << sourceListFile.string() << "\n"; + std::filesystem::remove(sourceListFile); + } + } + return 0; } std::vector<std::string> TaskFn::depends() const { - return {}; + std::vector<std::string> deps; + if(std::holds_alternative<ctor::GeneratorManyToOne>(config.function)) + { + for(const auto& src : config.sources) + { + if(src.source_type == ctor::source_type::generated) + { + std::filesystem::path _src = std::filesystem::path(settings.builddir); + _src /= src.file; + deps.push_back(_src.string()); + } + } + } + return deps; } std::string TaskFn::target() const @@ -110,7 +233,17 @@ std::string TaskFn::target() const std::filesystem::path TaskFn::targetFile() const { - return std::filesystem::path(settings.builddir) / sourceDir / _targetFile; + return std::filesystem::path(settings.builddir) / _targetFile; +} + +std::string TaskFn::sourceListString() const +{ + std::string sourceListStr; + for(const auto& source : config.sources) + { + sourceListStr += " " + source.file; + } + return sourceListStr; } bool TaskFn::derived() const diff --git a/src/task_fn.h b/src/task_fn.h index 1bad32c..84b4c2a 100644 --- a/src/task_fn.h +++ b/src/task_fn.h @@ -28,6 +28,7 @@ public: std::string target() const override; std::filesystem::path targetFile() const override; + std::string sourceListString() const; bool derived() const override; std::string toJSON() const override; @@ -37,8 +38,10 @@ public: protected: std::filesystem::path sourceFile; std::filesystem::path _targetFile; + std::filesystem::path sourceListFile; const ctor::build_configuration& config; const ctor::settings& settings; - std::filesystem::path sourceDir; + + std::vector<std::string> sources; }; diff --git a/src/task_ld.cc b/src/task_ld.cc index a3f02d1..a1cff34 100644 --- a/src/task_ld.cc +++ b/src/task_ld.cc @@ -20,7 +20,6 @@ TaskLD::TaskLD(const ctor::build_configuration& config_, : Task(config_, settings_, sourceDir_) , config(config_) , settings(settings_) - , sourceDir(sourceDir_) , is_self(is_self_) { target_type = config.type; @@ -40,8 +39,8 @@ TaskLD::TaskLD(const ctor::build_configuration& config_, objectFiles.push_back(objectFile); dependsStr.push_back(objectFile.string()); } - - flagsFile = std::filesystem::path(settings.builddir) / cleanUp(sourceDir) / targetFile().stem(); + auto cleaned_source_dir = cleanUp(sourceDir.string()); + flagsFile = std::filesystem::path(settings.builddir) / cleaned_source_dir / targetFile().stem(); flagsFile += ".flags"; source_language = ctor::language::c; diff --git a/src/task_ld.h b/src/task_ld.h index 85f680a..9dce4b4 100644 --- a/src/task_ld.h +++ b/src/task_ld.h @@ -43,6 +43,5 @@ private: const ctor::build_configuration& config; const ctor::settings& settings; - std::string sourceDir; bool is_self; }; diff --git a/src/tasks.cc b/src/tasks.cc index 7de8af9..fb7d72b 100644 --- a/src/tasks.cc +++ b/src/tasks.cc @@ -85,7 +85,7 @@ std::vector<std::shared_ptr<Task>> taskFactory(const ctor::build_configuration& ctor::target_type target_type{config.type}; if(target_type == ctor::target_type::automatic) { - if(config.function != nullptr) + if(!std::holds_alternative<std::monostate>(config.function)) { target_type = ctor::target_type::function; } @@ -114,12 +114,22 @@ std::vector<std::shared_ptr<Task>> taskFactory(const ctor::build_configuration& #ifndef BOOTSTRAP else { - for(const auto& source : config.sources) + bool multi{std::holds_alternative<ctor::GeneratorManyToOne>(config.function)}; + if(multi) { - auto task = std::make_shared<TaskFn>(config, settings, sourceDir, source); + auto task = std::make_shared<TaskFn>(config, settings, sourceDir, ""); tasks.push_back(task); objects.push_back(task->target()); } + else + { + for(const auto& source : config.sources) + { + auto task = std::make_shared<TaskFn>(config, settings, sourceDir, source); + tasks.push_back(task); + objects.push_back(task->target()); + } + } } #endif diff --git a/test/generated_sources_test.cc b/test/generated_sources_test.cc index 1ea7538..8c46983 100644 --- a/test/generated_sources_test.cc +++ b/test/generated_sources_test.cc @@ -14,6 +14,7 @@ public: GeneratedSourcesTest() { uTEST(GeneratedSourcesTest::test_custom_output); + uTEST(GeneratedSourcesTest::test_many_to_one_output); } void setup() @@ -74,6 +75,60 @@ public: } uASSERT(found); } + + void test_many_to_one_output() + { + using namespace std::string_literals; + + ctor::reg( + [](const ctor::settings&) + { + return ctor::build_configurations{ + { + .target = "test1", + .sources = { + {"foo.cc", ctor::source_type::generated} + } + }, + { + .target = "foo.cc", + .sources = { + {"bar.x"}, + {"bar.y"}, + }, + .function = [](const std::vector<std::string>& input, + const std::string& output, + const ctor::build_configuration& config, + const ctor::settings& settings) + { + return 0; + } + }, + }; + }); + ctor::settings settings{}; + auto tasks = getTasks(settings); + for(auto task : tasks) + { + uASSERT(task->registerDepTasks(tasks) == 0); + } + uASSERT_EQUAL(4u, tasks.size()); + bool found{false}; + for(const auto& task : tasks) + { + if(task->target() == "test1") + { + auto deps_test1 = task->getDependsTasks(); + uASSERT_EQUAL(1u, deps_test1.size()); + auto deps_foo_o = deps_test1[0]->getDependsTasks(); + uASSERT_EQUAL(1u, deps_foo_o.size()); + uASSERT_EQUAL("test/bar.x"s, deps_foo_o[0]->source()); + found = true; + } + } + uASSERT(found); + } + }; // Registers the fixture into the 'registry' diff --git a/test/suite/ctor_files/ctor.cc.generated b/test/suite/ctor_files/ctor.cc.generated index 5f82fd4..5bc2940 100644 --- a/test/suite/ctor_files/ctor.cc.generated +++ b/test/suite/ctor_files/ctor.cc.generated @@ -4,6 +4,7 @@ #include <ctor.h> #include <filesystem> #include <iostream> +#include <fstream> namespace { @@ -41,6 +42,44 @@ ctor::build_configurations ctorConfigs(const ctor::settings& settings) return 0; } }, + + { + .target = "many_to_one", + .sources = { + {"many_to_one.cc", ctor::source_type::generated} + } + }, + { + .target = "many_to_one.cc", + .sources = { + {"foo.cc", ctor::source_type::generated}, + {"hello.cc"}, + }, + .function = [](const std::vector<std::string>& input, + const std::string& output, + const ctor::build_configuration& config, + const ctor::settings& settings) + { + std::cout << "Output: " << output << '\n'; + std::ofstream ofs(output); + bool comment{true}; + for(const auto& input_file : input) + { + std::cout << "Input: " << input_file << '\n'; + std::ifstream ifs(input_file); + std::string line; + while(std::getline(ifs, line)) + { + ofs << line << '\n'; + } + if(comment) ofs << "/*\n"; + comment = false; + } + ofs << "*/\n"; + return 0; + } + }, + }; } } diff --git a/test/suite/ctor_files/ctor.cc.generated2 b/test/suite/ctor_files/ctor.cc.generated2 new file mode 100644 index 0000000..c78489f --- /dev/null +++ b/test/suite/ctor_files/ctor.cc.generated2 @@ -0,0 +1,86 @@ +// -*- c++ -*- +// Distributed under the BSD 2-Clause License. +// See accompanying file LICENSE for details. +#include <ctor.h> +#include <filesystem> +#include <iostream> +#include <fstream> + +namespace +{ +ctor::build_configurations ctorConfigs(const ctor::settings& settings) +{ + return + { + { + .target = "world", + .sources = { + { "world.cc", ctor::source_type::generated }, + }, + }, + { + .target = "foo", + .sources = { + { "foo.cc", ctor::source_type::generated }, + }, + }, + { + .target = "this_is_unused", + .sources = { + {"hello.cc", ctor::output_file{"world.cc"}}, + {"hello.cc", ctor::output_file{"foo.cc"}}, + }, + .function = [](const std::string& input, + const std::string& output, + const ctor::build_configuration& config, + const ctor::settings& settings) + { + namespace fs = std::filesystem; + std::cout << "Input: " << input << '\n'; + std::cout << "Output: " << output << '\n'; + fs::copy_file(input, output, fs::copy_options::overwrite_existing); + return 0; + } + }, + + { + .target = "many_to_one", + .sources = { + {"many_to_one.cc", ctor::source_type::generated} + } + }, + { + .target = "many_to_one.cc", + .sources = { + {"hello.cc"}, + }, + .function = [](const std::vector<std::string>& input, + const std::string& output, + const ctor::build_configuration& config, + const ctor::settings& settings) + { + std::cout << "Output: " << output << '\n'; + std::ofstream ofs(output); + bool comment{true}; + for(const auto& input_file : input) + { + std::cout << "Input: " << input_file << '\n'; + std::ifstream ifs(input_file); + std::string line; + while(std::getline(ifs, line)) + { + ofs << line << '\n'; + } + if(comment) ofs << "/*\n"; + comment = false; + } + ofs << "*/\n"; + return 0; + } + }, + + }; +} +} + +REG(ctorConfigs); diff --git a/test/suite/test.cc b/test/suite/test.cc index 0ab1299..bb62d9d 100644 --- a/test/suite/test.cc +++ b/test/suite/test.cc @@ -14,28 +14,45 @@ using namespace std::chrono_literals; -std::vector<std::string> tokenize(const std::string& str) -{ - std::vector<std::string> 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; + exit(value); } const std::string ctor_exe{"./ctor"}; const std::string obj_ext{".o"}; +void run_ctor(const std::vector<std::string>& args, + const std::source_location location = std::source_location::current()) +{ + ctor::settings settings{.verbose = 2}; + auto ret = execute(settings, ctor_exe, args); + if(ret != 0) + { + fail(ret, location); + } +} + +void assert_not_exists(const std::string& path, + const std::source_location location = std::source_location::current()) +{ + if(!std::filesystem::exists(path)) + { + fail(1, location); + } +} + +void assert_exists(const std::string& path, + const std::source_location location = std::source_location::current()) +{ + if(std::filesystem::exists(path)) + { + fail(1, location); + } +} + void copy_config(std::string cfg) { std::cout << "** ctor_files/ctor.cc." + cfg + "\n"; @@ -48,6 +65,50 @@ void copy_config(std::string cfg) } } +class Tracker +{ +public: + Tracker(const std::string& file_) : file(file_) + { + capture(); // capture initial value + } + + void capture() + { + changed(); + } + + bool changed() + { + auto tmp = readFile(file); + auto content_changed = tmp != content; + content = tmp; + return content_changed; + } + +private: + std::string file; + std::string content; +}; + +void assert_not_changed(Tracker& tracker, + const std::source_location location = std::source_location::current()) +{ + if(tracker.changed()) + { + fail(1, location); + } +} + +void assert_changed(Tracker& tracker, + const std::source_location location = std::source_location::current()) +{ + if(!tracker.changed()) + { + fail(1, location); + } +} + int main() { ctor::settings settings{}; @@ -65,291 +126,244 @@ int main() 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::filesystem::remove(ctor_exe); ////////////////////////////////////////////////////////////////////////////// - copy_config("base"); - - // Compile bootstrap binary - std::vector<std::string> 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()) + // bootstrap { - auto tokens = tokenize(CXXFLAGS); - for(const auto& token : tokens) + auto cxx_prog = locate(CXX, paths); + + std::vector<std::string> args = + {"-pthread", "-std=c++20", "-L", CTORDIR, "-lctor", "-I", "../../src", + "ctor.cc", "-o", ctor_exe}; + if(!CXXFLAGS.empty()) { - args.push_back(token); + auto tokens = argsplit(CXXFLAGS); + for(const auto& token : tokens) + { + args.push_back(token); + } } - } - if(!LDFLAGS.empty()) - { - auto tokens = tokenize(LDFLAGS); - for(const auto& token : tokens) + if(!LDFLAGS.empty()) { - args.push_back(token); + auto tokens = argsplit(LDFLAGS); + for(const auto& token : tokens) + { + args.push_back(token); + } } - } - auto ret = execute(settings, cxx_prog, args); - if(ret != 0) - { - return fail(ret); + // Compile bootstrap binary + copy_config("base"); + auto ret = execute(settings, cxx_prog, args); + if(ret != 0) + { + fail(ret); + } } - ////////////////////////////////////////////////////////////////////////////// + // check if source file changes are tracked { - // No build files should have been created yet - if(std::filesystem::exists(BUILDDIR)) - { - return fail(); - } + // No build files should have been created yet + assert_exists(BUILDDIR); - // 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); - } + // capture ctor binary before configure is called + Tracker ctor_bin(ctor_exe); + run_ctor( + {"configure", "--ctor-includedir", "../../src", + "--ctor-libdir=" + CTORDIR, "--build-dir=" + BUILDDIR}); - // 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(); - } + // ctor should be rebuilt at this point, so binary should have changed + assert_changed(ctor_bin); - // configuration.cc should have been generated now - if(!std::filesystem::exists("configuration.cc")) - { - return fail(); - } - if(!std::filesystem::exists("config.h")) - { - return fail(); - } + // configuration.cc should have been generated now + assert_not_exists("configuration.cc"); + assert_not_exists("config.h"); - // Shouldn't compile anything yet - only configure - if(std::filesystem::exists(BUILDDIR + "/hello-hello_cc" + obj_ext)) - { - return fail(); - } + // Shouldn't compile anything yet - only configure + assert_exists(BUILDDIR + "/hello-hello_cc" + obj_ext); - ctor_bin = readFile(ctor_exe); + ctor_bin.capture(); - // Run normally to build project - args = {"-v"}; - ret = execute(settings, ctor_exe, args); - if(ret != 0) - { - return fail(ret); - } + // Run normally to build project + run_ctor({"-v"}); - // Compiled object should now exist - if(!std::filesystem::exists(BUILDDIR + "/hello-hello_cc" + obj_ext)) - { - return fail(); - } + // Compiled object should now exist + assert_not_exists(BUILDDIR + "/hello-hello_cc" + obj_ext); - // ctor should not have been rebuilt, so binary should be the same - ctor_bin2 = readFile(ctor_exe); - if(ctor_bin != ctor_bin2) - { - return fail(); - } + // ctor should not have been rebuilt, so binary should be the same + assert_not_changed(ctor_bin); - std::this_thread::sleep_for(1100ms); + 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); + 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); - } + // Run normally to rebuild hello.cc + run_ctor({"-v"}); - // Object file should have been recompiled - auto time2 = - std::filesystem::last_write_time(BUILDDIR + "/hello-hello_cc" + obj_ext); - if(time == time2) - { - return fail(); - } + // Object file should have been recompiled + auto time2 = + std::filesystem::last_write_time(BUILDDIR + "/hello-hello_cc" + obj_ext); + if(time == time2) + { + 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); - } + // check if flags change trigger rebuild + { + // Replace -DFOO with -DBAR in foo external.cxxflags + copy_config("bar"); + Tracker configuration_cc_bin("configuration.cc"); + Tracker ctor_bin(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 + run_ctor({"-v"}); + + auto time2 = + std::filesystem::last_write_time(BUILDDIR + "/hello-hello_cc" + obj_ext); + if(time == time2) + { + fail(); + } - auto time2 = - std::filesystem::last_write_time(BUILDDIR + "/hello-hello_cc" + obj_ext); - if(time == time2) - { - return fail(); + assert_changed(configuration_cc_bin); + assert_changed(ctor_bin); } - auto configuration_cc_bin2 = readFile("configuration.cc"); - if(configuration_cc_bin == configuration_cc_bin2) + ////////////////////////////////////////////////////////////////////////////// + // check if included files in ctor.cc is tracked for changes { - return fail(); - } + copy_config("multi"); + Tracker configuration_cc_bin("configuration.cc"); + Tracker ctor_bin(ctor_exe); + auto time = + std::filesystem::last_write_time(BUILDDIR + "/hello-hello_cc" + obj_ext); + std::this_thread::sleep_for(1100ms); - auto ctor_bin2 = readFile(ctor_exe); - if(ctor_bin == ctor_bin2) - { - return fail(); - } + // Run normally to reconfigure, rebuild ctor and rebuild hello.cc + run_ctor({"-v"}); + + auto time2 = + std::filesystem::last_write_time(BUILDDIR + "/hello-hello_cc" + obj_ext); + if(time == time2) + { + fail(); + } + + assert_changed(configuration_cc_bin); + assert_changed(ctor_bin); + + // 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 + run_ctor({"-v"}); + + time2 = std::filesystem::last_write_time(ctor_exe); + if(time == time2) + { + fail(); + } } ////////////////////////////////////////////////////////////////////////////// + // generated part1: one-to-one generation { - 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); - } + copy_config("generated"); + std::filesystem::remove(BUILDDIR + "/world.cc"); + std::filesystem::remove(BUILDDIR + "/foo.cc"); - auto time2 = - std::filesystem::last_write_time(BUILDDIR + "/hello-hello_cc" + obj_ext); - if(time == time2) - { - return fail(); - } + Tracker configuration_cc_bin("configuration.cc"); + Tracker ctor_bin(ctor_exe); + std::this_thread::sleep_for(1100ms); - auto configuration_cc_bin2 = readFile("configuration.cc"); - if(configuration_cc_bin == configuration_cc_bin2) - { - return fail(); - } + // Run normally to reconfigure, rebuild ctor and build world.cc + run_ctor({"-v", "world"}); - auto ctor_bin2 = readFile(ctor_exe); - if(ctor_bin == ctor_bin2) - { - return fail(); - } + assert_changed(configuration_cc_bin); + assert_changed(ctor_bin); - // 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); + // foo.cc should not be generated at this point + assert_exists(BUILDDIR+"/foo.cc"); - // 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 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); - time2 = std::filesystem::last_write_time(ctor_exe); - if(time == time2) - { - return fail(); - } + // now touching hello.cc, should trigger regeneration of world.cc and + // rebuild + std::filesystem::last_write_time("hello.cc", time_w + 1s); + run_ctor({"-v", "world"}); + + 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) + { + fail(); + } + if(time_wo == time_wo2) + { + fail(); + } } ////////////////////////////////////////////////////////////////////////////// + // generated part2: many-to-one generation { - copy_config("generated"); - std::filesystem::remove(BUILDDIR + "/world.cc"); - std::filesystem::remove(BUILDDIR + "/foo.cc"); + std::filesystem::remove(BUILDDIR + "/world.cc"); + std::filesystem::remove(BUILDDIR + "/foo.cc"); + std::filesystem::remove(BUILDDIR + "/many_to_one.cc"); - auto configuration_cc_bin = readFile("configuration.cc"); - auto ctor_bin = readFile(ctor_exe); - std::this_thread::sleep_for(1100ms); + run_ctor({"-v", "many_to_one"}); - // 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); - } + // world.cc should not be generated at this point + assert_exists(BUILDDIR+"/world.cc"); - auto configuration_cc_bin2 = readFile("configuration.cc"); - if(configuration_cc_bin == configuration_cc_bin2) - { - return fail(); - } + // foo.cc should have been generated at this point + assert_not_exists(BUILDDIR+"/foo.cc"); - auto ctor_bin2 = readFile(ctor_exe); - if(ctor_bin == ctor_bin2) - { - return fail(); - } + // many_to_one.cc should have been generated + assert_not_exists(BUILDDIR+"/many_to_one.cc"); - // foo.cc should not be generated at this point - if(std::filesystem::exists(BUILDDIR+"/foo.cc")) - { - return fail(); - } + auto time = std::filesystem::last_write_time(BUILDDIR + "/many_to_one.cc"); + std::this_thread::sleep_for(1100ms); - 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); + Tracker ctor_bin(ctor_exe); - // 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); - } + // remove "foo.cc" from sources list, so it only contains hello.cc + copy_config("generated2"); - 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(); - } + // rebuild + run_ctor({"-v", "many_to_one"}); + + // Verify that the change resulted in a ctor rebuild + assert_changed(ctor_bin); + + // Verify that source-list change triggered a new build of many_to_one.cc + auto time2 = + std::filesystem::last_write_time(BUILDDIR + "/many_to_one.cc"); + if(time == time2) + { + fail(); + } } return 0; |
