summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBent Bisballe Nyeng <deva@aasimon.org>2025-12-25 18:24:30 +0100
committerBent Bisballe Nyeng <deva@aasimon.org>2025-12-26 15:50:05 +0100
commit312aa38263b5e014b04a9055f842e83d876af6ea (patch)
treecc335604c3ec8f9a8276733d6b4b5e1e6ccd0e7b
parent3091c5b12717a44a67962b9e245b2de8069a7cf5 (diff)
Decorate sources as 'generated' to make sure they inject a dependency to their generators, and look for the sources in the build folder instead of the source folder.generated_sources
-rw-r--r--src/ctor.h12
-rw-r--r--src/task_cc.cc8
-rw-r--r--src/task_fn.cc3
-rw-r--r--src/tasks.cc4
-rw-r--r--test/ctor.cc17
-rw-r--r--test/generated_sources_test.cc80
6 files changed, 121 insertions, 3 deletions
diff --git a/src/ctor.h b/src/ctor.h
index 8dd2ddd..f145eef 100644
--- a/src/ctor.h
+++ b/src/ctor.h
@@ -67,6 +67,12 @@ struct output_file
std::string file;
};
+enum class source_type
+{
+ regular,
+ generated,
+};
+
struct source
{
template <class ... Args>
@@ -74,6 +80,7 @@ struct source
std::is_convertible_v<Args, std::string_view> ||
std::is_same_v<Args, ctor::toolchain> ||
std::is_same_v<Args, ctor::language> ||
+ std::is_same_v<Args, ctor::source_type> ||
std::is_same_v<Args, ctor::output_file>
) && ...)
constexpr source(Args && ... arg)
@@ -96,6 +103,10 @@ struct source
{
output = arg.file;
}
+ else if constexpr(std::is_same_v<Args, ctor::source_type>)
+ {
+ source_type = arg;
+ }
}(), ...);
}
@@ -103,6 +114,7 @@ struct source
ctor::toolchain toolchain{ctor::toolchain::any};
ctor::language language{ctor::language::automatic};
std::string output{};
+ ctor::source_type source_type{ctor::source_type::regular};
};
enum class cxx_opt
diff --git a/src/task_cc.cc b/src/task_cc.cc
index 9628455..f81023f 100644
--- a/src/task_cc.cc
+++ b/src/task_cc.cc
@@ -23,6 +23,10 @@ TaskCC::TaskCC(const ctor::build_configuration& config_, const ctor::settings& s
, sourceDir(sourceDir_)
, _source(source)
{
+ if(source.source_type == ctor::source_type::generated)
+ {
+ sourceFile = std::filesystem::path(settings.builddir) / sourceFile;
+ }
sourceFile /= source.file;
std::filesystem::path base = sourceFile.parent_path();
@@ -252,6 +256,10 @@ int TaskCC::clean()
std::vector<std::string> TaskCC::depends() const
{
+ if(_source.source_type == ctor::source_type::generated)
+ {
+ return {sourceFile.string()};
+ }
return {};
}
diff --git a/src/task_fn.cc b/src/task_fn.cc
index b6b50ea..ebfdac6 100644
--- a/src/task_fn.cc
+++ b/src/task_fn.cc
@@ -24,6 +24,7 @@ TaskFn::TaskFn(const ctor::build_configuration& config_, const ctor::settings& s
target_type = config.type;
source_language = source.language;
+ std::filesystem::path base = sourceFile.parent_path();
if(source.output.empty())
{
@@ -31,7 +32,7 @@ TaskFn::TaskFn(const ctor::build_configuration& config_, const ctor::settings& s
exit(1);
}
- _targetFile = source.output;
+ _targetFile = base / source.output;
}
bool TaskFn::dirtyInner()
diff --git a/src/tasks.cc b/src/tasks.cc
index 94fe269..7de8af9 100644
--- a/src/tasks.cc
+++ b/src/tasks.cc
@@ -114,9 +114,9 @@ std::vector<std::shared_ptr<Task>> taskFactory(const ctor::build_configuration&
#ifndef BOOTSTRAP
else
{
- for(const auto& file : config.sources)
+ for(const auto& source : config.sources)
{
- auto task = std::make_shared<TaskFn>(config, settings, sourceDir, file);
+ auto task = std::make_shared<TaskFn>(config, settings, sourceDir, source);
tasks.push_back(task);
objects.push_back(task->target());
}
diff --git a/test/ctor.cc b/test/ctor.cc
index e33dc77..8b89f6d 100644
--- a/test/ctor.cc
+++ b/test/ctor.cc
@@ -28,6 +28,23 @@ ctor::build_configurations ctorTestConfigs(const ctor::settings& settings)
{
.type = ctor::target_type::unit_test,
.system = ctor::output_system::build,
+ .target = "generated_sources_test",
+ .sources = {
+ "generated_sources_test.cc",
+ "testmain.cc",
+ },
+ .depends = { "libctor_nomain.a" },
+ .flags = {
+ .cxxflags = {
+ "-std=c++20", "-O3", "-Wall",
+ "-I../src", "-Iuunit",
+ "-DOUTPUT=\"generated_sources\"",
+ },
+ },
+ },
+ {
+ .type = ctor::target_type::unit_test,
+ .system = ctor::output_system::build,
.target = "argsplit_test",
.sources = {
"argsplit_test.cc",
diff --git a/test/generated_sources_test.cc b/test/generated_sources_test.cc
new file mode 100644
index 0000000..53bde62
--- /dev/null
+++ b/test/generated_sources_test.cc
@@ -0,0 +1,80 @@
+// -*- c++ -*-
+// Distributed under the BSD 2-Clause License.
+// See accompanying file LICENSE for details.
+#include <uunit.h>
+
+#include <ctor.h>
+#include <tasks.h>
+#include <rebuild.h>
+
+class GeneratedSourcesTest
+ : public uUnit
+{
+public:
+ GeneratedSourcesTest()
+ {
+ uTEST(GeneratedSourcesTest::test_custom_output);
+ }
+
+ void setup()
+ {
+ // Make sure we start from a clean slate
+ getConfigFileList().clear();
+ }
+
+ void test_custom_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 = "this_is_unused",
+ .sources = {
+ {"bar.x", ctor::output_file{"foo.cc"}},
+ {"bar.y", ctor::output_file{"bar.cc"}},
+ },
+ .function = [](const 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'
+static GeneratedSourcesTest test;