summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Jenkinsfile56
-rw-r--r--README.md2
-rwxr-xr-xbootstrap.sh10
-rw-r--r--ctor.cc9
-rw-r--r--examples/cppbuild.cc2
-rw-r--r--examples/ctor.cc2
-rw-r--r--examples/subdir/ctor.cc2
-rw-r--r--src/bootstrap.cc45
-rw-r--r--src/build.cc49
-rw-r--r--src/build.h21
-rw-r--r--src/configure.cc300
-rw-r--r--src/configure.h8
-rw-r--r--src/ctor.h268
-rw-r--r--src/execute.cc2
-rw-r--r--src/externals.h6
-rw-r--r--src/externals_manual.cc35
-rw-r--r--src/externals_manual.h15
-rw-r--r--src/libctor.cc21
-rw-r--r--src/libctor.h123
-rw-r--r--src/rebuild.cc64
-rw-r--r--src/rebuild.h10
-rw-r--r--src/settings.h13
-rw-r--r--src/task.cc59
-rw-r--r--src/task.h42
-rw-r--r--src/task_ar.cc102
-rw-r--r--src/task_ar.h19
-rw-r--r--src/task_cc.cc244
-rw-r--r--src/task_cc.h21
-rw-r--r--src/task_fn.cc121
-rw-r--r--src/task_fn.h44
-rw-r--r--src/task_ld.cc119
-rw-r--r--src/task_ld.h19
-rw-r--r--src/task_so.cc100
-rw-r--r--src/task_so.h19
-rw-r--r--src/tasks.cc98
-rw-r--r--src/tasks.h25
-rw-r--r--src/tools.cc648
-rw-r--r--src/tools.h96
-rw-r--r--src/unittest.cc22
-rw-r--r--src/unittest.h11
-rw-r--r--src/util.cc33
-rw-r--r--src/util.h16
-rw-r--r--test/ctor.cc64
-rw-r--r--test/source_type_test.cc42
-rw-r--r--test/suite/ctor_files/ctor.cc.bar18
-rw-r--r--test/suite/ctor_files/ctor.cc.base19
-rw-r--r--test/suite/ctor_files/ctor.cc.multi18
-rwxr-xr-xtest/suite/test.sh32
-rw-r--r--test/tasks_test.cc111
-rw-r--r--test/tools_test.cc930
50 files changed, 3330 insertions, 825 deletions
diff --git a/Jenkinsfile b/Jenkinsfile
new file mode 100644
index 0000000..c95b0eb
--- /dev/null
+++ b/Jenkinsfile
@@ -0,0 +1,56 @@
+pipeline {
+ agent { label 'c++20' }
+
+ stages {
+ stage('Clean') {
+ steps {
+ echo 'Cleaning workspace ...'
+ sh 'rm -Rf build*'
+ }
+ }
+ stage('Build-gcc') {
+ steps {
+ echo 'Building (gcc) ...'
+ sh 'BUILDDIR=build-gcc CXX=g++ ./bootstrap.sh'
+ }
+ }
+ stage('Test-gcc') {
+ steps {
+ echo 'Testing (gcc) ...'
+ sh './ctor check'
+ }
+ }
+ stage('Test-suite-gcc') {
+ steps {
+ echo 'Testing suite (gcc) ...'
+ sh '(cd test/suite; CTORDIR=../../build-gcc CXX=g++ ./test.sh)'
+ }
+ }
+ stage('Build-clang') {
+ steps {
+ echo 'Building (clang) ...'
+ sh 'BUILDDIR=build-clang CXX=clang++ ./bootstrap.sh'
+ }
+ }
+ stage('Test-clang') {
+ steps {
+ echo 'Testing (clang) ...'
+ sh './ctor check'
+ }
+ }
+ stage('Test-suite-clang') {
+ steps {
+ echo 'Testing suite (clang) ...'
+ sh '(cd test/suite; CTORDIR=../../build-clang CXX=clang++ ./test.sh)'
+ }
+ }
+ }
+
+ post {
+ always {
+ xunit(thresholds: [ skipped(failureThreshold: '0'),
+ failed(failureThreshold: '0') ],
+ tools: [ CppUnit(pattern: 'build-*/test/*.xml') ])
+ }
+ }
+}
diff --git a/README.md b/README.md
index caad51d..1a02be1 100644
--- a/README.md
+++ b/README.md
@@ -16,7 +16,7 @@ Step 1: Create a build configuration, in C++
A really simple example ('hello_config.cc'):
```c++
-#include "libctor.h"
+#include "ctor.h"
namespace
{
diff --git a/bootstrap.sh b/bootstrap.sh
index a5c11ac..76503bb 100755
--- a/bootstrap.sh
+++ b/bootstrap.sh
@@ -1,7 +1,11 @@
#!/bin/sh
+: ${CXX:=g++}
+: ${BUILDDIR:=build}
+CXX=$(which $CXX)
+
echo "Bootstrapping..."
-g++ -std=c++20 -Wall -O3 -Isrc -pthread src/bootstrap.cc ctor.cc test/ctor.cc -o ctor && \
+$CXX -std=c++20 -Wall -O3 -Isrc -pthread src/bootstrap.cc ctor.cc test/ctor.cc -o ctor && \
./ctor && \
-g++ -std=c++20 -Wall -O3 -Isrc -pthread ctor.cc test/ctor.cc -Lbuild -lctor -o ctor && \
-./ctor configure --ctor-includedir=src --ctor-libdir=build && \
+$CXX -std=c++20 -Wall -O3 -Isrc -pthread ctor.cc test/ctor.cc -L$BUILDDIR -lctor -o ctor && \
+./ctor configure --ctor-includedir=src --ctor-libdir=$BUILDDIR --build-dir=$BUILDDIR&& \
echo "Done. Now run ./ctor to (re)build."
diff --git a/ctor.cc b/ctor.cc
index c8c7cff..c9faa5e 100644
--- a/ctor.cc
+++ b/ctor.cc
@@ -1,29 +1,32 @@
// -*- c++ -*-
// Distributed under the BSD 2-Clause License.
// See accompanying file LICENSE for details.
-#include <libctor.h>
+#include <ctor.h>
namespace
{
-BuildConfigurations ctorConfigs()
+ctor::build_configurations ctorConfigs(const ctor::settings& settings)
{
return
{
{
- .type = TargetType::StaticLibrary,
+ .type = ctor::target_type::static_library,
.target = "libctor.a",
.sources = {
"src/build.cc",
"src/configure.cc",
"src/execute.cc",
+ "src/externals_manual.cc",
"src/libctor.cc",
"src/rebuild.cc",
"src/task.cc",
"src/task_ar.cc",
+ "src/task_fn.cc",
"src/task_cc.cc",
"src/task_ld.cc",
"src/task_so.cc",
"src/tasks.cc",
+ "src/tools.cc",
"src/util.cc",
"src/unittest.cc",
},
diff --git a/examples/cppbuild.cc b/examples/cppbuild.cc
index eafac8d..9e1014f 100644
--- a/examples/cppbuild.cc
+++ b/examples/cppbuild.cc
@@ -1,4 +1,4 @@
-#include "libctor.h"
+#include "ctor.h"
namespace
{
diff --git a/examples/ctor.cc b/examples/ctor.cc
index 1a02e90..6ed8c6c 100644
--- a/examples/ctor.cc
+++ b/examples/ctor.cc
@@ -1,7 +1,7 @@
// -*- c++ -*-
// Distributed under the BSD 2-Clause License.
// See accompanying file LICENSE for details.
-#include "libctor.h"
+#include "ctor.h"
namespace
{
diff --git a/examples/subdir/ctor.cc b/examples/subdir/ctor.cc
index b5f5885..2e3de9f 100644
--- a/examples/subdir/ctor.cc
+++ b/examples/subdir/ctor.cc
@@ -1,7 +1,7 @@
// -*- c++ -*-
// Distributed under the BSD 2-Clause License.
// See accompanying file LICENSE for details.
-#include "../libctor.h"
+#include "../ctor.h"
namespace
{
diff --git a/src/bootstrap.cc b/src/bootstrap.cc
index 08f7b1f..0604527 100644
--- a/src/bootstrap.cc
+++ b/src/bootstrap.cc
@@ -3,11 +3,11 @@
// See accompanying file LICENSE for details.
#include <iostream>
#include <array>
+#include <cstdlib>
#define BOOTSTRAP
-#include "libctor.h"
-#include "settings.h"
+#include "ctor.h"
#include "util.cc"
#include "rebuild.cc"
@@ -17,25 +17,44 @@
#include "execute.cc"
#include "tasks.cc"
#include "build.cc"
+#include "tools.cc"
std::filesystem::path configurationFile("configuration.cc");
std::filesystem::path configHeaderFile("config.h");
-const Configuration default_configuration{};
-const Configuration& configuration()
+const ctor::configuration& ctor::get_configuration()
{
- return default_configuration;
+ static ctor::configuration cfg;
+ static bool initialised{false};
+ if(!initialised)
+ {
+ cfg.host_toolchain = getToolChain(cfg.get(ctor::cfg::host_cxx, "/usr/bin/g++"));
+ initialised = true;
+ }
+
+ return cfg;
}
-bool hasConfiguration(const std::string& key)
+bool ctor::configuration::has(const std::string& key) const
{
return false;
}
-const std::string& getConfiguration(const std::string& key,
- const std::string& defaultValue)
+const std::string& ctor::configuration::get(const std::string& key, const std::string& default_value) const
{
- return defaultValue;
+ if(key == ctor::cfg::host_cxx && std::getenv("CXX"))
+ {
+ static std::string s = std::getenv("CXX");
+ return s;
+ }
+
+ if(key == ctor::cfg::builddir && std::getenv("BUILDDIR"))
+ {
+ static std::string s = std::getenv("BUILDDIR");
+ return s;
+ }
+
+ return default_value;
}
int main(int argc, char* argv[])
@@ -47,9 +66,10 @@ int main(int argc, char* argv[])
return 1;
}
- Settings settings{};
+ ctor::settings settings{};
- settings.builddir = getConfiguration(cfg::builddir, "build");
+ const auto& c = ctor::get_configuration();
+ settings.builddir = c.get(ctor::cfg::builddir, settings.builddir);
settings.parallel_processes =
std::max(1u, std::thread::hardware_concurrency() * 2 - 1);
settings.verbose = 0;
@@ -66,7 +86,8 @@ int main(int argc, char* argv[])
auto& targets = getTargets(settings);
for(const auto& target : targets)
{
- if(target.config.type != TargetType::UnitTest)
+ if(target.config.type != ctor::target_type::unit_test &&
+ target.config.type != ctor::target_type::unit_test_library)
{
non_unittest_targets.push_back(target);
}
diff --git a/src/build.cc b/src/build.cc
index 8adbc54..ad30719 100644
--- a/src/build.cc
+++ b/src/build.cc
@@ -9,13 +9,16 @@
#include <chrono>
#include <set>
#include <thread>
+#include <list>
+
+#include "ctor.h"
using namespace std::chrono_literals;
-int build(const Settings& settings,
+int build(const ctor::settings& settings,
const std::string& name,
- const std::list<std::shared_ptr<Task>>& tasks,
- const std::list<std::shared_ptr<Task>>& all_tasks,
+ const std::set<std::shared_ptr<Task>>& tasks,
+ const std::set<std::shared_ptr<Task>>& all_tasks,
bool dryrun)
{
if(settings.verbose > 1)
@@ -23,12 +26,12 @@ int build(const Settings& settings,
std::cout << "Building '" << name << "'\n";
}
- std::list<std::shared_ptr<Task>> dirtyTasks;
+ std::set<std::shared_ptr<Task>> dirtyTasks;
for(auto task : tasks)
{
if(task->dirty())
{
- dirtyTasks.push_back(task);
+ dirtyTasks.insert(task);
}
}
@@ -81,7 +84,9 @@ int build(const Settings& settings,
return task->run();
}));
started_one = true;
- std::this_thread::sleep_for(2ms);
+ // Make sure we don't start tasks on top of each other to prevent
+ // straining the disk.
+ std::this_thread::sleep_for(50ms);
}
for(auto process = processes.begin();
@@ -103,13 +108,9 @@ int build(const Settings& settings,
break;
}
- if(started_one)
- {
- std::this_thread::sleep_for(2ms);
- }
- else
+ if(!started_one) // prevent polling too fast if no task is yet ready
{
- std::this_thread::sleep_for(200ms);
+ std::this_thread::sleep_for(10ms);
}
}
@@ -153,29 +154,23 @@ std::set<std::shared_ptr<Task>> getDepTasks(std::shared_ptr<Task> task)
}
}
-int build(const Settings& settings,
+int build(const ctor::settings& settings,
const std::string& name,
- const std::list<std::shared_ptr<Task>>& all_tasks,
+ const std::set<std::shared_ptr<Task>>& all_tasks,
bool dryrun)
{
bool task_found{false};
for(auto task : all_tasks)
{
- if(task->target() == name || // match exact target output (ex. build/foo.o)
-
- (!task->derived() && // if non-derived task:
- ( task->buildConfig().target == name || // match name
- task->buildConfig().name == name ) // or target
- )
- )
+ if(*task == name)
{
task_found = true;
auto depSet = getDepTasks(task);
- std::list<std::shared_ptr<Task>> ts;
+ std::set<std::shared_ptr<Task>> ts;
for(const auto& task : depSet)
{
- ts.push_back(task);
+ ts.insert(task);
}
auto ret = build(settings, name, ts, all_tasks, dryrun);
@@ -197,14 +192,14 @@ int build(const Settings& settings,
return 0;
}
-int build(const Settings& settings,
+int build(const ctor::settings& settings,
const std::string& name,
const std::vector<Target>& targets,
- const std::list<std::shared_ptr<Task>>& all_tasks,
+ const std::set<std::shared_ptr<Task>>& all_tasks,
bool dryrun)
{
bool task_found{false};
- std::list<std::shared_ptr<Task>> ts;
+ std::set<std::shared_ptr<Task>> ts;
for(const auto& target : targets)
{
@@ -218,7 +213,7 @@ int build(const Settings& settings,
auto depSet = getDepTasks(task);
for(const auto& task : depSet)
{
- ts.push_back(task);
+ ts.insert(task);
}
}
}
diff --git a/src/build.h b/src/build.h
index 7be7517..d74642c 100644
--- a/src/build.h
+++ b/src/build.h
@@ -4,29 +4,32 @@
#pragma once
#include <string>
-#include <list>
+#include <set>
#include <memory>
#include "task.h"
-#include "settings.h"
#include "tasks.h"
+namespace ctor {
+struct settings;
+} // namespace ctor::
+
//! Dry-run returns number of dirty tasks but otherwise does nothing.
-int build(const Settings& settings,
+int build(const ctor::settings& settings,
const std::string& name,
- const std::list<std::shared_ptr<Task>>& tasks,
- const std::list<std::shared_ptr<Task>>& all_tasks,
+ const std::set<std::shared_ptr<Task>>& tasks,
+ const std::set<std::shared_ptr<Task>>& all_tasks,
bool dryrun = false);
//! Dry-run returns number of dirty tasks but otherwise does nothing.
-int build(const Settings& settings,
+int build(const ctor::settings& settings,
const std::string& name,
- const std::list<std::shared_ptr<Task>>& all_tasks,
+ const std::set<std::shared_ptr<Task>>& all_tasks,
bool dryrun = false);
//! Dry-run returns number of dirty tasks but otherwise does nothing.
-int build(const Settings& settings,
+int build(const ctor::settings& settings,
const std::string& name,
const std::vector<Target>& targets,
- const std::list<std::shared_ptr<Task>>& all_tasks,
+ const std::set<std::shared_ptr<Task>>& all_tasks,
bool dryrun = false);
diff --git a/src/configure.cc b/src/configure.cc
index 4df6026..8e88092 100644
--- a/src/configure.cc
+++ b/src/configure.cc
@@ -10,63 +10,91 @@
#include <getoptpp/getoptpp.hpp>
-#include "settings.h"
#include "execute.h"
-#include "libctor.h"
+#include "ctor.h"
#include "tasks.h"
#include "rebuild.h"
+#include "externals.h"
+#include "tools.h"
std::filesystem::path configurationFile("configuration.cc");
std::filesystem::path configHeaderFile("config.h");
-const Configuration default_configuration{};
-const Configuration& __attribute__((weak)) configuration()
+std::map<std::string, std::string> external_includedir;
+std::map<std::string, std::string> external_libdir;
+
+const ctor::configuration& __attribute__((weak)) ctor::get_configuration()
{
- return default_configuration;
+ static ctor::configuration cfg;
+ static bool initialised{false};
+ if(!initialised)
+ {
+ cfg.host_toolchain = getToolChain(cfg.get(ctor::cfg::host_cxx, "g++"));
+ initialised = true;
+ }
+ return cfg;
}
-namespace ctor
-{
+namespace ctor {
std::optional<std::string> includedir;
std::optional<std::string> libdir;
-}
+std::optional<std::string> builddir;
+std::map<std::string, std::string> conf_values;
+} // ctor::
-bool hasConfiguration(const std::string& key)
+bool ctor::configuration::has(const std::string& key) const
{
- if(key == cfg::ctor_includedir && ctor::includedir)
+ if(key == ctor::cfg::ctor_includedir && ctor::includedir)
{
return true;
}
- if(key == cfg::ctor_libdir && ctor::libdir)
+ if(key == ctor::cfg::ctor_libdir && ctor::libdir)
{
return true;
}
- const auto& c = configuration();
- return c.tools.find(key) != c.tools.end();
+ if(key == ctor::cfg::builddir && ctor::builddir)
+ {
+ return true;
+ }
+
+ if(ctor::conf_values.find(key) != ctor::conf_values.end())
+ {
+ return true;
+ }
+
+ return tools.find(key) != tools.end();
}
-const std::string& getConfiguration(const std::string& key,
- const std::string& defaultValue)
+const std::string& ctor::configuration::get(const std::string& key, const std::string& default_value) const
{
- if(key == cfg::ctor_includedir && ctor::includedir)
+ if(key == ctor::cfg::ctor_includedir && ctor::includedir)
{
return *ctor::includedir;
}
- if(key == cfg::ctor_libdir && ctor::libdir)
+ if(key == ctor::cfg::ctor_libdir && ctor::libdir)
{
return *ctor::libdir;
}
- const auto& c = configuration();
- if(hasConfiguration(key))
+ if(key == ctor::cfg::builddir && ctor::builddir)
+ {
+ return *ctor::builddir;
+ }
+
+ if(ctor::conf_values.find(key) != ctor::conf_values.end())
{
- return c.tools.at(key);
+ return ctor::conf_values[key];
}
- return defaultValue;
+ if(has(key))
+ {
+ return tools.at(key);
+ }
+
+ return default_value;
}
std::string locate(const std::string& arch, const std::string& app)
@@ -143,11 +171,71 @@ public:
}
};
-int regenerateCache(const Settings& default_settings,
+namespace {
+std::ostream& operator<<(std::ostream& stream, const ctor::toolchain& toolchain)
+{
+ switch(toolchain)
+ {
+ case ctor::toolchain::any:
+ stream << "ctor::toolchain::any";
+ break;
+ case ctor::toolchain::none:
+ stream << "ctor::toolchain::none";
+ break;
+ case ctor::toolchain::gcc:
+ stream << "ctor::toolchain::gcc";
+ break;
+ case ctor::toolchain::clang:
+ stream << "ctor::toolchain::clang";
+ break;
+ }
+ return stream;
+}
+
+std::ostream& operator<<(std::ostream& ostr, const ctor::c_flag& flag)
+{
+ for(const auto& s : to_strings(ctor::toolchain::any, flag))
+ {
+ ostr << s;
+ }
+ return ostr;
+}
+
+std::ostream& operator<<(std::ostream& ostr, const ctor::cxx_flag& flag)
+{
+ for(const auto& s : to_strings(ctor::toolchain::any, flag))
+ {
+ ostr << s;
+ }
+ return ostr;
+}
+
+std::ostream& operator<<(std::ostream& ostr, const ctor::ld_flag& flag)
+{
+ for(const auto& s : to_strings(ctor::toolchain::any, flag))
+ {
+ ostr << s;
+ }
+ return ostr;
+}
+
+std::ostream& operator<<(std::ostream& ostr, const ctor::asm_flag& flag)
+{
+ for(const auto& s : to_strings(ctor::toolchain::any, flag))
+ {
+ ostr << s;
+ }
+ return ostr;
+}
+}
+
+// helper constant for the visitor
+template<class> inline constexpr bool always_false_v = false;
+
+int regenerateCache(ctor::settings& settings,
const std::vector<std::string>& args,
const std::map<std::string, std::string>& env)
{
- Settings settings{default_settings};
Args vargs(args);
dg::Options opt;
@@ -163,12 +251,14 @@ int regenerateCache(const Settings& default_settings,
std::string ld_prog = "ld";
std::string ctor_includedir;
std::string ctor_libdir;
+ std::string builddir;
opt.add("build-dir", required_argument, 'b',
"Set output directory for build files (default: '" +
settings.builddir + "').",
[&]() {
settings.builddir = optarg;
+ builddir = optarg;
return 0;
});
@@ -249,6 +339,51 @@ int regenerateCache(const Settings& default_settings,
return 0;
});
+ // Resolv externals
+ ctor::external_configurations externalConfigs;
+ for(std::size_t i = 0; i < numExternalConfigFiles; ++i)
+ {
+ auto newExternalConfigs = externalConfigFiles[i].cb(settings);
+ externalConfigs.insert(externalConfigs.end(),
+ newExternalConfigs.begin(),
+ newExternalConfigs.end());
+ }
+
+ auto add_path_args =
+ [&](const std::string& name)
+ {
+ opt.add(name + "-includedir", required_argument, key++,
+ "Set path to " + name + " header file.",
+ [&]() {
+ external_includedir[name] = optarg;
+ return 0;
+ });
+
+ opt.add(name + "-libdir", required_argument, key++,
+ "Set path to " + name + " libraries.",
+ [&]() {
+ external_libdir[name] = optarg;
+ return 0;
+ });
+ };
+
+ for(const auto& ext : externalConfigs)
+ {
+ std::visit([&](auto&& arg)
+ {
+ using T = std::decay_t<decltype(arg)>;
+ if constexpr (std::is_same_v<T, ctor::external_manual>)
+ {
+ add_path_args(ext.name);
+ }
+ else
+ {
+ static_assert(always_false_v<T>, "non-exhaustive visitor!");
+ }
+ }, ext.external);
+
+ }
+
opt.add("help", no_argument, 'h',
"Print this help text.",
[&]() {
@@ -325,24 +460,38 @@ int regenerateCache(const Settings& default_settings,
std::string build_ar = locate(build_arch, ar_prog);
std::string build_ld = locate(build_arch, ld_prog);
- // Resolv externals
- ExternalConfigurations externalConfigs;
- for(std::size_t i = 0; i < numExternalConfigFiles; ++i)
+ if(!host_cxx.empty())
{
- auto newExternalConfigs = externalConfigFiles[i].cb();
- externalConfigs.insert(externalConfigs.end(),
- newExternalConfigs.begin(),
- newExternalConfigs.end());
+ // This is needed for bootstrapping (when running configure for the first time)
+ ctor::conf_values[ctor::cfg::host_cxx] = host_cxx;
}
+ // Store current values for execution in this execution context.
+ if(!ctor_includedir.empty())
+ {
+ ctor::conf_values[ctor::cfg::ctor_includedir] = ctor_includedir;
+ }
+ if(!ctor_libdir.empty())
+ {
+ ctor::conf_values[ctor::cfg::ctor_libdir] = ctor_libdir;
+ }
+ if(!builddir.empty())
+ {
+ ctor::conf_values[ctor::cfg::builddir] = builddir;
+ }
+ ctor::conf_values[ctor::cfg::host_cxx] = host_cxx;
+ ctor::conf_values[ctor::cfg::build_cxx] = build_cxx;
+
std::cout << "Writing results to: " << configurationFile.string() << "\n";
{
std::ofstream istr(configurationFile);
- istr << "#include <libctor.h>\n\n";
- istr << "const Configuration& configuration()\n";
+ istr << "#include <ctor.h>\n\n";
+ istr << "const ctor::configuration& ctor::get_configuration()\n";
istr << "{\n";
- istr << " static Configuration cfg =\n";
+ istr << " static ctor::configuration cfg =\n";
istr << " {\n";
+ istr << " .host_toolchain = " << getToolChain(host_cxx) << ",\n";
+ istr << " .build_toolchain = " << getToolChain(build_cxx) << ",\n";
istr << " .args = {";
for(const auto& arg : args)
{
@@ -357,69 +506,88 @@ int regenerateCache(const Settings& default_settings,
istr << "},\n";
istr << " .tools = {\n";
- istr << " { \"" << cfg::builddir << "\", \"" << settings.builddir << "\" },\n";
- istr << " { \"" << cfg::host_cc << "\", \"" << host_cc << "\" },\n";
- istr << " { \"" << cfg::host_cxx << "\", \"" << host_cxx << "\" },\n";
- istr << " { \"" << cfg::host_ar << "\", \"" << host_ar << "\" },\n";
- istr << " { \"" << cfg::host_ld << "\", \"" << host_ld << "\" },\n";
- istr << " { \"" << cfg::build_cc << "\", \"" << build_cc << "\" },\n";
- istr << " { \"" << cfg::build_cxx << "\", \"" << build_cxx << "\" },\n";
- istr << " { \"" << cfg::build_ar << "\", \"" << build_ar << "\" },\n";
- istr << " { \"" << cfg::build_ld << "\", \"" << build_ld << "\" },\n";
+ if(!builddir.empty())
+ {
+ istr << " { \"" << ctor::cfg::builddir << "\", \"" << builddir << "\" },\n";
+ ctor::builddir = builddir;
+ }
+ istr << " { \"" << ctor::cfg::host_cc << "\", \"" << host_cc << "\" },\n";
+ istr << " { \"" << ctor::cfg::host_cxx << "\", \"" << host_cxx << "\" },\n";
+ istr << " { \"" << ctor::cfg::host_ar << "\", \"" << host_ar << "\" },\n";
+ istr << " { \"" << ctor::cfg::host_ld << "\", \"" << host_ld << "\" },\n";
+ istr << " { \"" << ctor::cfg::build_cc << "\", \"" << build_cc << "\" },\n";
+ istr << " { \"" << ctor::cfg::build_cxx << "\", \"" << build_cxx << "\" },\n";
+ istr << " { \"" << ctor::cfg::build_ar << "\", \"" << build_ar << "\" },\n";
+ istr << " { \"" << ctor::cfg::build_ld << "\", \"" << build_ld << "\" },\n";
if(!ctor_includedir.empty())
{
- istr << " { \"" << cfg::ctor_includedir << "\", \"" << ctor_includedir << "\" },\n";
+ istr << " { \"" << ctor::cfg::ctor_includedir << "\", \"" << ctor_includedir << "\" },\n";
ctor::includedir = ctor_includedir;
}
if(!ctor_libdir.empty())
{
- istr << " { \"" << cfg::ctor_libdir << "\", \"" << ctor_libdir << "\" },\n";
+ istr << " { \"" << ctor::cfg::ctor_libdir << "\", \"" << ctor_libdir << "\" },\n";
ctor::libdir = ctor_libdir;
}
istr << " },\n";
istr << " .externals = {\n";
- for(const auto& externalConfig : externalConfigs)
+ for(const auto& ext : externalConfigs)
{
- istr << " { \"" << externalConfig.name << "\", {\n";
+ istr << " { \"" << ext.name << "\", {\n";
+ ctor::flags resolved_flags;
+ if(std::holds_alternative<ctor::external_manual>(ext.external))
+ {
+ if(auto ret = resolv(settings, ext,
+ std::get<ctor::external_manual>(ext.external),
+ resolved_flags))
+ {
+ return ret;
+ }
+ }
+ else
+ {
+ std::cout << "Unknown external type\n";
+ return 1;
+ }
- if(!externalConfig.flags.cxxflags.empty())
+ if(!resolved_flags.cflags.empty())
{
- istr << " .cxxflags = {";
- for(const auto& flag : externalConfig.flags.cxxflags)
+ istr << " .cflags = {";
+ for(const auto& flag : resolved_flags.cflags)
{
- istr << "\"" << flag << "\",";
+ istr << flag << ",";
}
istr << "},\n";
}
- if(!externalConfig.flags.cflags.empty())
+ if(!resolved_flags.cxxflags.empty())
{
- istr << " .cflags = {";
- for(const auto& flag : externalConfig.flags.cflags)
+ istr << " .cxxflags = {";
+ for(const auto& flag : resolved_flags.cxxflags)
{
- istr << "\"" << flag << "\",";
+ istr << flag << ",";
}
istr << "},\n";
}
- if(!externalConfig.flags.ldflags.empty())
+ if(!resolved_flags.ldflags.empty())
{
istr << " .ldflags = {";
- for(const auto& flag : externalConfig.flags.ldflags)
+ for(const auto& flag : resolved_flags.ldflags)
{
- istr << "\"" << flag << "\",";
+ istr << flag << ",";
}
istr << "},\n";
}
- if(!externalConfig.flags.asmflags.empty())
+ if(!resolved_flags.asmflags.empty())
{
istr << " .asmflags = {";
- for(const auto& flag : externalConfig.flags.asmflags)
+ for(const auto& flag : resolved_flags.asmflags)
{
- istr << "\"" << flag << "\",";
+ istr << flag << ",";
}
istr << "},\n";
}
@@ -429,7 +597,7 @@ int regenerateCache(const Settings& default_settings,
istr << " },\n";
istr << " };\n";
istr << " return cfg;\n";
- istr << "}\n\n";
+ istr << "}\n";
}
{
@@ -442,9 +610,9 @@ int regenerateCache(const Settings& default_settings,
return 0;
}
-int configure(const Settings& global_settings, int argc, char* argv[])
+int configure(const ctor::settings& global_settings, int argc, char* argv[])
{
- Settings settings{global_settings};
+ ctor::settings settings{global_settings};
std::vector<std::string> args;
for(int i = 2; i < argc; ++i) // skip command and the first 'configure' arg
@@ -488,8 +656,10 @@ int configure(const Settings& global_settings, int argc, char* argv[])
return 0;
}
-int reconfigure(const Settings& settings, int argc, char* argv[])
+int reconfigure(const ctor::settings& global_settings, int argc, char* argv[])
{
+ ctor::settings settings{global_settings};
+
bool no_rerun{false};
std::vector<std::string> args;
@@ -503,7 +673,7 @@ int reconfigure(const Settings& settings, int argc, char* argv[])
args.push_back(argv[i]);
}
- const auto& cfg = configuration();
+ const auto& cfg = ctor::get_configuration();
std::cout << "Re-running configure:\n";
for(const auto& e : cfg.env)
diff --git a/src/configure.h b/src/configure.h
index 16499d6..ac8d721 100644
--- a/src/configure.h
+++ b/src/configure.h
@@ -8,10 +8,12 @@
#include <map>
#include <vector>
-struct Settings;
+namespace ctor {
+struct settings;
+} // namespace ctor::
extern std::filesystem::path configurationFile;;
extern std::filesystem::path configHeaderFile;
-int configure(const Settings& settings, int argc, char* argv[]);
-int reconfigure(const Settings& settings, int argc, char* argv[]);
+int configure(const ctor::settings& settings, int argc, char* argv[]);
+int reconfigure(const ctor::settings& settings, int argc, char* argv[]);
diff --git a/src/ctor.h b/src/ctor.h
new file mode 100644
index 0000000..b8b3ae6
--- /dev/null
+++ b/src/ctor.h
@@ -0,0 +1,268 @@
+// -*- c++ -*-
+// Distributed under the BSD 2-Clause License.
+// See accompanying file LICENSE for details.
+#pragma once
+
+#include <source_location>
+#include <string>
+#include <vector>
+#include <map>
+#include <variant>
+#include <cstddef>
+#include <functional>
+
+namespace ctor {
+
+enum class target_type
+{
+ automatic, // Default - deduce from target name and sources extensions
+
+ executable,
+ static_library,
+ dynamic_library,
+ object,
+ unit_test,
+ unit_test_library,
+ function,
+};
+
+enum class language
+{
+ automatic, // Default - deduce language from source extensions
+
+ c,
+ cpp,
+ assembler,
+};
+
+enum class output_system
+{
+ host, // Output for the target system
+ build, // Internal tool during cross-compilation
+};
+
+struct source
+{
+ source(const char* file) : file(file) {}
+ source(const std::string& file) : file(file) {}
+ source(const char* file, ctor::language lang) : file(file), language(lang) {}
+ source(const std::string& file, ctor::language lang) : file(file), language(lang) {}
+
+ source(const char* file, const char* output) : file(file), output(output) {}
+ source(const std::string& file, const std::string& output) : file(file), output(output) {}
+ source(const char* file, ctor::language lang, const char* output) : file(file), language(lang), output(output) {}
+ source(const std::string& file, ctor::language lang, const std::string& output) : file(file), language(lang), output(output) {}
+
+ std::string file;
+ ctor::language language{ctor::language::automatic};
+ std::string output{};
+};
+
+enum class toolchain
+{
+ any,
+ none,
+ gcc,
+ clang,
+};
+
+enum class cxx_opt
+{
+ // gcc/clang
+ output, // -o
+ debug, // -g
+ warn_all, // -Wall
+ warnings_as_errors, // -Werror
+ generate_dep_tree, // -MMD
+ no_link, // -c
+ include_path, // -I<arg>
+ cpp_std, // -std=<arg>
+ optimization, // -O<arg>
+ position_independent_code, // -fPIC
+ position_independent_executable, // -fPIE
+ custom, // entire option taken verbatim from <arg>
+};
+
+enum class c_opt
+{
+ // gcc/clang
+ output, // -o
+ debug, // -g
+ warn_all, // -Wall
+ warnings_as_errors, // -Werror
+ generate_dep_tree, // -MMD
+ no_link, // -c
+ include_path, // -I<arg>
+ c_std, // -std=<arg>
+ optimization, // -O<arg>
+ position_independent_code, // -fPIC
+ position_independent_executable, // -fPIE
+ custom, // entire option taken verbatim from <arg>
+};
+
+enum class ld_opt
+{
+ // gcc/clang
+ output, // -o
+ strip, // -s
+ warn_all, // -Wall
+ warnings_as_errors, // -Werror
+ library_path, // -L<arg>
+ link, // -l<arg>
+ cpp_std, // -std=<arg>
+ build_shared, // -shared
+ threads, // -pthread
+ position_independent_code, // -fPIC
+ position_independent_executable, // -fPIE
+ custom, // entire option taken verbatim from <arg>
+};
+
+enum class ar_opt
+{
+ // gcc/clang
+ replace, // -r
+ add_index, // -s
+ create, // -c
+ output, // <arg>
+
+ custom, // entire option taken verbatim from <arg>
+};
+
+enum class asm_opt
+{
+ // gcc/clang
+ custom, // entire option taken verbatim from <arg>
+};
+
+template<typename T>
+class flag
+{
+public:
+ flag(const std::string& str);
+ flag(const char* str);
+ flag(T opt) : opt(opt) {}
+ flag(T opt, const std::string& arg) : opt(opt), arg(arg) {}
+ flag(T opt, const char* arg) : opt(opt), arg(arg) {}
+ flag(ctor::toolchain toolchain, T opt) : toolchain(toolchain), opt(opt) {}
+ flag(ctor::toolchain toolchain, T opt, const char* arg) : toolchain(toolchain), opt(opt), arg(arg) {}
+ flag(ctor::toolchain toolchain, T opt, const std::string& arg) : toolchain(toolchain), opt(opt), arg(arg) {}
+
+ ctor::toolchain toolchain{ctor::toolchain::any};
+ T opt;
+ std::string arg;
+};
+
+using c_flag = ctor::flag<ctor::c_opt>;
+using cxx_flag = ctor::flag<ctor::cxx_opt>;
+using ld_flag = ctor::flag<ctor::ld_opt>;
+using ar_flag = ctor::flag<ctor::ar_opt>;
+using asm_flag = ctor::flag<ctor::asm_opt>;
+
+using c_flags = std::vector<ctor::c_flag>;
+using cxx_flags = std::vector<ctor::cxx_flag>;
+using ld_flags= std::vector<ctor::ld_flag>;
+using ar_flags = std::vector<ctor::ar_flag>;
+using asm_flags = std::vector<ctor::asm_flag>;
+
+struct flags
+{
+ ctor::c_flags cflags; // flags for c compiler
+ ctor::cxx_flags cxxflags; // flags for c++ compiler
+ ctor::ld_flags ldflags; // flags for linker
+ ctor::ar_flags arflags; // flags for archiver
+ ctor::asm_flags asmflags; // flags for asm translator
+};
+
+struct settings
+{
+ std::string builddir{"build"};
+ std::size_t parallel_processes{1};
+ int verbose{0}; // -1: completely silent, 0: normal, 1: verbose, ...
+};
+
+struct build_configuration;
+using GeneratorCb = std::function<int(const std::string& input,
+ const std::string& output,
+ const build_configuration& config,
+ const ctor::settings& settings)>;
+
+struct build_configuration
+{
+ std::string name; // Name - used for referring in other configurations.
+ ctor::target_type type{ctor::target_type::automatic};
+ ctor::output_system system{ctor::output_system::host};
+ std::string target; // Output target file for this configuration
+ std::vector<ctor::source> sources; // source list
+ std::vector<std::string> depends; // internal target dependencies
+ ctor::flags flags;
+ std::vector<std::string> externals; // externals used by this configuration
+ GeneratorCb function;
+};
+
+using build_configurations = std::vector<build_configuration>;
+
+int reg(ctor::build_configurations (*cb)(const ctor::settings&),
+ const std::source_location location = std::source_location::current());
+
+// This type will use flags verbatim
+struct external_manual
+{
+ ctor::flags flags;
+};
+
+
+struct external_configuration
+{
+ std::string name; // Name for configuration
+ ctor::output_system system{ctor::output_system::host};
+ std::variant<ctor::external_manual> external;
+};
+
+using external_configurations = std::vector<ctor::external_configuration>;
+
+int reg(ctor::external_configurations (*cb)(const ctor::settings&),
+ const std::source_location location = std::source_location::current());
+
+// Convenience macro - ugly but keeps things simple(r)
+#define CONCAT(a, b) CONCAT_INNER(a, b)
+#define CONCAT_INNER(a, b) a ## b
+#define UNIQUE_NAME(base) CONCAT(base, __LINE__)
+#define REG(cb) namespace { int UNIQUE_NAME(unique) = reg(cb); }
+
+// Predefined configuration keys
+namespace cfg
+{
+constexpr auto builddir = "builddir";
+
+constexpr auto host_cc = "host-cc";
+constexpr auto host_cxx = "host-cpp";
+constexpr auto host_ar = "host-ar";
+constexpr auto host_ld = "host-ld";
+
+constexpr auto build_cc = "build-cc";
+constexpr auto build_cxx = "build-cpp";
+constexpr auto build_ar = "build-ar";
+constexpr auto build_ld = "build-ld";
+
+constexpr auto ctor_includedir = "ctor-includedir";
+constexpr auto ctor_libdir = "ctor-libdir";
+}
+
+struct configuration
+{
+ bool has(const std::string& key) const;
+ const std::string& get(const std::string& key, const std::string& default_value = {}) const;
+
+ ctor::toolchain host_toolchain{ctor::toolchain::none};
+ ctor::toolchain build_toolchain{ctor::toolchain::none};
+
+ std::vector<std::string> args; // vector of arguments used when last calling configure
+ std::map<std::string, std::string> env; // env used when last calling configure
+
+ std::map<std::string, std::string> tools; // tools
+ std::map<std::string, ctor::flags> externals;
+};
+
+const ctor::configuration& get_configuration();
+
+} // ctor::
diff --git a/src/execute.cc b/src/execute.cc
index 610ccdd..20a4a02 100644
--- a/src/execute.cc
+++ b/src/execute.cc
@@ -61,7 +61,7 @@ int execute(const std::string& command,
cmd += arg;
}
- std::cout << cmd << "\n";
+ std::cout << cmd << std::endl;
}
#if 1
diff --git a/src/externals.h b/src/externals.h
new file mode 100644
index 0000000..7b4aa23
--- /dev/null
+++ b/src/externals.h
@@ -0,0 +1,6 @@
+// -*- c++ -*-
+// Distributed under the BSD 2-Clause License.
+// See accompanying file LICENSE for details.
+#pragma once
+
+#include "externals_manual.h"
diff --git a/src/externals_manual.cc b/src/externals_manual.cc
new file mode 100644
index 0000000..3b96263
--- /dev/null
+++ b/src/externals_manual.cc
@@ -0,0 +1,35 @@
+// -*- c++ -*-
+// Distributed under the BSD 2-Clause License.
+// See accompanying file LICENSE for details.
+#include "externals_manual.h"
+
+#include <map>
+
+#include "ctor.h"
+
+#include "util.h"
+#include "tools.h"
+
+extern std::map<std::string, std::string> external_includedir;
+extern std::map<std::string, std::string> external_libdir;
+
+int resolv(const ctor::settings& settings, const ctor::external_configuration& config,
+ const ctor::external_manual& ext, ctor::flags& flags)
+{
+ flags = ext.flags;
+
+ auto inc = external_includedir.find(config.name);
+ if(inc != external_includedir.end())
+ {
+ flags.cflags.push_back({ctor::c_opt::include_path, inc->second});
+ flags.cxxflags.push_back({ctor::cxx_opt::include_path, inc->second});
+ }
+
+ auto lib = external_libdir.find(config.name);
+ if(lib != external_libdir.end())
+ {
+ flags.ldflags.push_back({ctor::ld_opt::library_path, lib->second});
+ }
+
+ return 0;
+}
diff --git a/src/externals_manual.h b/src/externals_manual.h
new file mode 100644
index 0000000..a906ab7
--- /dev/null
+++ b/src/externals_manual.h
@@ -0,0 +1,15 @@
+// -*- c++ -*-
+// Distributed under the BSD 2-Clause License.
+// See accompanying file LICENSE for details.
+#pragma once
+
+namespace ctor {
+struct settings;
+struct external_configuration;
+struct external_manual;
+struct flags;
+} // namespace ctor::
+
+int resolv(const ctor::settings& settings,
+ const ctor::external_configuration& name,
+ const ctor::external_manual& ext, ctor::flags& flags);
diff --git a/src/libctor.cc b/src/libctor.cc
index a2c873e..21792e1 100644
--- a/src/libctor.cc
+++ b/src/libctor.cc
@@ -19,8 +19,7 @@
#include <getoptpp/getoptpp.hpp>
-#include "libctor.h"
-#include "settings.h"
+#include "ctor.h"
#include "configure.h"
#include "rebuild.h"
#include "tasks.h"
@@ -29,9 +28,10 @@
int main(int argc, char* argv[])
{
- Settings settings{};
+ ctor::settings settings{};
+ const auto& c = ctor::get_configuration();
- settings.builddir = getConfiguration(cfg::builddir, settings.builddir);
+ settings.builddir = c.get(ctor::cfg::builddir, settings.builddir);
settings.parallel_processes =
std::max(1u, std::thread::hardware_concurrency()) * 2 - 1;
@@ -264,13 +264,13 @@ Options:
if(print_configure_cmd)
{
no_default_build = true;
- std::cout << getConfiguration("cmd") << "\n";
+ std::cout << c.get("cmd") << "\n";
}
if(print_configure_db)
{
no_default_build = true;
- const auto& c = configuration();
+ const auto& c = ctor::get_configuration();
for(const auto& config : c.tools)
{
std::cout << config.first << ": " << config.second << "\n";
@@ -316,7 +316,8 @@ Options:
auto& targets = getTargets(settings);
for(const auto& target : targets)
{
- if(target.config.type == TargetType::UnitTest)
+ if(target.config.type == ctor::target_type::unit_test ||
+ target.config.type == ctor::target_type::unit_test_library)
{
unittest_targets.push_back(target);
}
@@ -338,7 +339,8 @@ Options:
auto& targets = getTargets(settings);
for(const auto& target : targets)
{
- if(target.config.type != TargetType::UnitTest)
+ if(target.config.type != ctor::target_type::unit_test &&
+ target.config.type != ctor::target_type::unit_test_library)
{
non_unittest_targets.push_back(target);
}
@@ -367,7 +369,8 @@ Options:
auto& targets = getTargets(settings);
for(const auto& target : targets)
{
- if(target.config.type != TargetType::UnitTest)
+ if(target.config.type != ctor::target_type::unit_test &&
+ target.config.type != ctor::target_type::unit_test_library)
{
non_unittest_targets.push_back(target);
}
diff --git a/src/libctor.h b/src/libctor.h
deleted file mode 100644
index 0af33cb..0000000
--- a/src/libctor.h
+++ /dev/null
@@ -1,123 +0,0 @@
-// -*- c++ -*-
-// Distributed under the BSD 2-Clause License.
-// See accompanying file LICENSE for details.
-#pragma once
-
-#include <source_location>
-#include <string>
-#include <vector>
-#include <map>
-
-enum class TargetType
-{
- Auto, // Default - deduce from target name and sources extensions
-
- Executable,
- StaticLibrary,
- DynamicLibrary,
- Object,
- UnitTest,
-};
-
-enum class Language
-{
- Auto, // Default - deduce language from source extensions
-
- C,
- Cpp,
- Asm,
-};
-
-enum class OutputSystem
-{
- Host, // Output for the target system
- Build, // Internal tool during cross-compilation
-};
-
-struct Source
-{
- Source(const char* file) : file(file) {}
- Source(const std::string& file) : file(file) {}
- Source(const char* file, Language lang) : file(file), language(lang) {}
- Source(const std::string& file, Language lang) : file(file), language(lang) {}
-
- std::string file;
- Language language{Language::Auto};
-};
-
-struct Flags
-{
- std::vector<std::string> cxxflags; // flags for c++ compiler
- std::vector<std::string> cflags; // flags for c compiler
- std::vector<std::string> ldflags; // flags for linker
- std::vector<std::string> asmflags; // flags for asm translator
-};
-
-struct BuildConfiguration
-{
- std::string name; // Name - used for referring in other configurations.
- TargetType type{TargetType::Auto};
- OutputSystem system{OutputSystem::Host};
- std::string target; // Output target file for this configuration
- std::vector<Source> sources; // source list
- std::vector<std::string> depends; // internal target dependencies
- Flags flags;
- std::vector<std::string> externals; // externals used by this configuration
-};
-
-using BuildConfigurations = std::vector<BuildConfiguration>;
-
-int reg(BuildConfigurations (*cb)(),
- const std::source_location location = std::source_location::current());
-
-
-struct ExternalConfiguration
-{
- std::string name; // Name for configuration
- Flags flags;
- std::vector<std::string> libs; // libraries
-};
-
-using ExternalConfigurations = std::vector<ExternalConfiguration>;
-
-int reg(ExternalConfigurations (*cb)(),
- const std::source_location location = std::source_location::current());
-
-// Convenience macro - ugly but keeps things simple(r)
-#define CONCAT(a, b) CONCAT_INNER(a, b)
-#define CONCAT_INNER(a, b) a ## b
-#define UNIQUE_NAME(base) CONCAT(base, __LINE__)
-#define REG(cb) namespace { int UNIQUE_NAME(unique) = reg(cb); }
-
-// Predefined configuration keys
-namespace cfg
-{
-constexpr auto builddir = "builddir";
-
-constexpr auto host_cc = "host-cc";
-constexpr auto host_cxx = "host-cpp";
-constexpr auto host_ar = "host-ar";
-constexpr auto host_ld = "host-ld";
-
-constexpr auto build_cc = "build-cc";
-constexpr auto build_cxx = "build-cpp";
-constexpr auto build_ar = "build-ar";
-constexpr auto build_ld = "build-ld";
-
-constexpr auto ctor_includedir = "ctor-includedir";
-constexpr auto ctor_libdir = "ctor-libdir";
-}
-
-struct Configuration
-{
- std::vector<std::string> args; // vector of arguments used when last calling configure
- std::map<std::string, std::string> env; // env used when last calling configure
-
- std::map<std::string, std::string> tools; // tools
- std::map<std::string, Flags> externals;
-};
-
-const Configuration& configuration();
-bool hasConfiguration(const std::string& key);
-const std::string& getConfiguration(const std::string& key,
- const std::string& defaultValue = {});
diff --git a/src/rebuild.cc b/src/rebuild.cc
index 50d7540..c97452d 100644
--- a/src/rebuild.cc
+++ b/src/rebuild.cc
@@ -7,18 +7,21 @@
#include <filesystem>
#include <algorithm>
#include <source_location>
+#include <cstring>
#include "configure.h"
-#include "settings.h"
-#include "libctor.h"
+#include "ctor.h"
#include "tasks.h"
#include "build.h"
#include "execute.h"
+#include "tools.h"
+#include "util.h"
std::array<BuildConfigurationEntry, 1024> configFiles;
std::size_t numConfigFiles{0};
-int reg(BuildConfigurations (*cb)(),
+namespace ctor {
+int reg(ctor::build_configurations (*cb)(const ctor::settings&),
const std::source_location location)
{
// NOTE: std::cout cannot be used here
@@ -29,12 +32,23 @@ int reg(BuildConfigurations (*cb)(),
exit(1);
}
- configFiles[numConfigFiles].file = location.file_name();
+ auto loc = std::filesystem::path(location.file_name());
+ if(loc.is_absolute())
+ {
+ auto pwd = std::filesystem::current_path();
+ auto rel = std::filesystem::relative(loc, pwd);
+ configFiles[numConfigFiles].file = strdup(rel.string().data()); // NOTE: This intentionally leaks memory
+ }
+ else
+ {
+ configFiles[numConfigFiles].file = location.file_name();
+ }
configFiles[numConfigFiles].cb = cb;
++numConfigFiles;
return 0;
}
+} // ctor::
int reg(const char* location)
{
@@ -48,7 +62,7 @@ int reg(const char* location)
configFiles[numConfigFiles].file = location;
configFiles[numConfigFiles].cb =
- [](){ return std::vector<BuildConfiguration>{}; };
+ [](const ctor::settings&){ return std::vector<ctor::build_configuration>{}; };
++numConfigFiles;
return 0;
@@ -97,7 +111,8 @@ int unreg(const char* location)
std::array<ExternalConfigurationEntry, 1024> externalConfigFiles;
std::size_t numExternalConfigFiles{0};
-int reg(ExternalConfigurations (*cb)(),
+namespace ctor {
+int reg(ctor::external_configurations (*cb)(const ctor::settings&),
const std::source_location location)
{
// NOTE: std::cout cannot be used here
@@ -114,10 +129,11 @@ int reg(ExternalConfigurations (*cb)(),
return 0;
}
+} // namespace ctor::
namespace
{
-bool contains(const std::vector<Source>& sources, const std::string& file)
+bool contains(const std::vector<ctor::source>& sources, const std::string& file)
{
for(const auto& source : sources)
{
@@ -131,7 +147,7 @@ bool contains(const std::vector<Source>& sources, const std::string& file)
}
}
-bool recompileCheck(const Settings& global_settings, int argc, char* argv[],
+bool recompileCheck(const ctor::settings& global_settings, int argc, char* argv[],
bool relaunch_allowed)
{
using namespace std::string_literals;
@@ -141,24 +157,28 @@ bool recompileCheck(const Settings& global_settings, int argc, char* argv[],
std::cout << "Recompile check (" << numConfigFiles << "):\n";
}
- BuildConfiguration config;
+ ctor::build_configuration config;
config.name = "ctor";
- config.flags.cxxflags =
- std::vector<std::string>({ "-s", "-O3", "-std=c++20" });
- if(hasConfiguration(cfg::ctor_includedir))
+ config.system = ctor::output_system::build;
+
+ config.flags.cxxflags.push_back({ctor::cxx_opt::optimization, "3"});
+ config.flags.cxxflags.push_back({ctor::cxx_opt::cpp_std, "c++20"});
+
+ const auto& c = ctor::get_configuration();
+ if(c.has(ctor::cfg::ctor_includedir))
{
- config.flags.cxxflags.push_back("-I"s + getConfiguration(cfg::ctor_includedir));
+ config.flags.cxxflags.push_back({ctor::cxx_opt::include_path,
+ c.get(ctor::cfg::ctor_includedir)});
}
- if(hasConfiguration(cfg::ctor_libdir))
+ if(c.has(ctor::cfg::ctor_libdir))
{
- config.flags.ldflags.push_back("-L"s + getConfiguration(cfg::ctor_libdir));
+ config.flags.ldflags.push_back({ctor::ld_opt::library_path, c.get(ctor::cfg::ctor_libdir)});
}
- config.flags.ldflags.push_back("-lctor");
- config.flags.ldflags.push_back("-pthread");
-
+ config.flags.ldflags.push_back({ctor::ld_opt::link, "ctor"});
+ config.flags.ldflags.push_back({ctor::ld_opt::threads});
- Settings settings{global_settings};
+ ctor::settings settings{global_settings};
settings.verbose = -1; // Make check completely silent.
settings.builddir += "/ctor"; // override builddir to use ctor subdir
@@ -229,7 +249,11 @@ bool recompileCheck(const Settings& global_settings, int argc, char* argv[],
if(dirty_tasks)
{
std::cout << "Rebuilding config.\n";
- build(settings, "ctor", tasks); // run for real
+ auto ret = build(settings, "ctor", tasks); // run for real
+ if(ret != 0)
+ {
+ return ret;
+ }
}
if(reconfigure)
diff --git a/src/rebuild.h b/src/rebuild.h
index 0845d30..efa6d42 100644
--- a/src/rebuild.h
+++ b/src/rebuild.h
@@ -6,20 +6,18 @@
#include <vector>
#include <array>
-#include "libctor.h"
-
-class Settings;
+#include "ctor.h"
struct BuildConfigurationEntry
{
const char* file;
- BuildConfigurations (*cb)();
+ ctor::build_configurations (*cb)(const ctor::settings&);
};
struct ExternalConfigurationEntry
{
const char* file;
- ExternalConfigurations (*cb)();
+ ctor::external_configurations (*cb)(const ctor::settings&);
};
extern std::array<BuildConfigurationEntry, 1024> configFiles;
@@ -32,5 +30,5 @@ int reg(const char* location);
int unreg(const char* location);
//! Returns true of recompilation was needed.
-bool recompileCheck(const Settings& settings, int argc, char* argv[],
+bool recompileCheck(const ctor::settings& settings, int argc, char* argv[],
bool relaunch_allowed = true);
diff --git a/src/settings.h b/src/settings.h
deleted file mode 100644
index 48e3619..0000000
--- a/src/settings.h
+++ /dev/null
@@ -1,13 +0,0 @@
-// -*- c++ -*-
-// Distributed under the BSD 2-Clause License.
-// See accompanying file LICENSE for details.
-#pragma once
-
-#include <cstddef>
-
-struct Settings
-{
- std::string builddir{"build"};
- std::size_t parallel_processes{1};
- int verbose{0}; // -1: completely silent, 0: normal, 1: verbose, ...
-};
diff --git a/src/task.cc b/src/task.cc
index 8a9eefa..817ee3a 100644
--- a/src/task.cc
+++ b/src/task.cc
@@ -6,22 +6,25 @@
#include <unistd.h>
#include <iostream>
-Task::Task(const BuildConfiguration& config)
+Task::Task(const ctor::build_configuration& config, const ctor::settings& settings,
+ const std::string& sourceDir)
: config(config)
, output_system(config.system)
+ , settings(settings)
+ , sourceDir(sourceDir)
{
}
-int Task::registerDepTasks(const std::list<std::shared_ptr<Task>>& tasks)
+int Task::registerDepTasks(const std::set<std::shared_ptr<Task>>& tasks)
{
for(const auto& depStr : depends())
{
bool found{false};
for(const auto& task : tasks)
{
- if(task->target() == depStr)
+ if(*task == depStr)
{
- dependsTasks.push_back(task);
+ dependsTasks.insert(task);
found = true;
}
}
@@ -33,16 +36,21 @@ int Task::registerDepTasks(const std::list<std::shared_ptr<Task>>& tasks)
}
}
- return 0;
+ return registerDepTasksInner(tasks);
+}
+
+bool Task::operator==(const std::string& depStr)
+{
+ return
+ name() == depStr ||
+ target() == depStr ||
+ sourceDir + "/" + target() == depStr ||
+ targetFile().string() == depStr
+ ;
}
std::string Task::name() const
{
- // If config name is not set, use target instead.
- if(config.name.empty())
- {
- return config.target;
- }
return config.name;
}
@@ -99,45 +107,46 @@ State Task::state() const
return task_state.load();
}
-const BuildConfiguration& Task::buildConfig() const
+const ctor::build_configuration& Task::buildConfig() const
{
return config;
}
-TargetType Task::targetType() const
+ctor::target_type Task::targetType() const
{
return target_type;
}
-Language Task::sourceLanguage() const
+ctor::language Task::sourceLanguage() const
{
return source_language;
}
-OutputSystem Task::outputSystem() const
+ctor::output_system Task::outputSystem() const
{
return output_system;
}
std::string Task::compiler() const
{
+ const auto& c = ctor::get_configuration();
switch(sourceLanguage())
{
- case Language::C:
+ case ctor::language::c:
switch(outputSystem())
{
- case OutputSystem::Host:
- return getConfiguration(cfg::host_cc, "/usr/bin/gcc");
- case OutputSystem::Build:
- return getConfiguration(cfg::build_cc, "/usr/bin/gcc");
+ case ctor::output_system::host:
+ return c.get(ctor::cfg::host_cc, "/usr/bin/gcc");
+ case ctor::output_system::build:
+ return c.get(ctor::cfg::build_cc, "/usr/bin/gcc");
}
- case Language::Cpp:
+ case ctor::language::cpp:
switch(outputSystem())
{
- case OutputSystem::Host:
- return getConfiguration(cfg::host_cxx, "/usr/bin/g++");
- case OutputSystem::Build:
- return getConfiguration(cfg::build_cxx, "/usr/bin/g++");
+ case ctor::output_system::host:
+ return c.get(ctor::cfg::host_cxx, "/usr/bin/g++");
+ case ctor::output_system::build:
+ return c.get(ctor::cfg::build_cxx, "/usr/bin/g++");
}
default:
std::cerr << "Unknown CC target type\n";
@@ -146,7 +155,7 @@ std::string Task::compiler() const
}
}
-std::list<std::shared_ptr<Task>> Task::getDependsTasks()
+std::set<std::shared_ptr<Task>> Task::getDependsTasks()
{
return dependsTasks;
}
diff --git a/src/task.h b/src/task.h
index 4cbd126..9e99f25 100644
--- a/src/task.h
+++ b/src/task.h
@@ -6,10 +6,11 @@
#include <vector>
#include <string>
#include <atomic>
-#include <list>
+#include <set>
#include <memory>
+#include <filesystem>
-#include "libctor.h"
+#include "ctor.h"
enum class State
{
@@ -23,9 +24,14 @@ enum class State
class Task
{
public:
- Task(const BuildConfiguration& config);
+ Task(const ctor::build_configuration& config, const ctor::settings& settings,
+ const std::string& sourceDir);
+ virtual ~Task() = default;
- int registerDepTasks(const std::list<std::shared_ptr<Task>>& tasks);
+ int registerDepTasks(const std::set<std::shared_ptr<Task>>& tasks);
+ virtual int registerDepTasksInner(const std::set<std::shared_ptr<Task>>& tasks) { return 0; }
+
+ bool operator==(const std::string& dep);
virtual std::string name() const;
bool dirty();
@@ -34,8 +40,14 @@ public:
State state() const;
virtual int clean() = 0 ;
virtual std::vector<std::string> depends() const = 0;
+
+ //! Raw target name as stated in ctor.cc config file or (in case of a derived
+ //! target) the calculated target without builddir prefix.
virtual std::string target() const = 0;
+ //! Target file with full path prefix
+ virtual std::filesystem::path targetFile() const = 0;
+
//! Returns true for tasks that are non-target tasks, ie. for example derived
//! objects files from target sources.
virtual bool derived() const = 0;
@@ -45,14 +57,14 @@ public:
//! Returns a reference to the originating build config.
//! Note: the build config of a derived task will be that of its parent
//! (target) task.
- const BuildConfiguration& buildConfig() const;
+ const ctor::build_configuration& buildConfig() const;
- TargetType targetType() const;
- Language sourceLanguage() const;
- OutputSystem outputSystem() const;
+ ctor::target_type targetType() const;
+ ctor::language sourceLanguage() const;
+ ctor::output_system outputSystem() const;
std::string compiler() const;
- std::list<std::shared_ptr<Task>> getDependsTasks();
+ std::set<std::shared_ptr<Task>> getDependsTasks();
virtual std::string source() const { return {}; }
@@ -62,9 +74,11 @@ protected:
virtual bool dirtyInner() { return false; }
std::vector<std::string> dependsStr;
- std::list<std::shared_ptr<Task>> dependsTasks;
- const BuildConfiguration& config;
- TargetType target_type{TargetType::Auto};
- Language source_language{Language::Auto};
- OutputSystem output_system{OutputSystem::Host};
+ std::set<std::shared_ptr<Task>> dependsTasks;
+ const ctor::build_configuration& config;
+ ctor::target_type target_type{ctor::target_type::automatic};
+ ctor::language source_language{ctor::language::automatic};
+ ctor::output_system output_system{ctor::output_system::host};
+ const ctor::settings& settings;
+ std::string sourceDir;
};
diff --git a/src/task_ar.cc b/src/task_ar.cc
index d4a4447..426a576 100644
--- a/src/task_ar.cc
+++ b/src/task_ar.cc
@@ -6,25 +6,24 @@
#include <iostream>
#include <fstream>
-#include "libctor.h"
-#include "settings.h"
+#include "ctor.h"
#include "execute.h"
#include "util.h"
+#include "tools.h"
-TaskAR::TaskAR(const BuildConfiguration& config,
- const Settings& settings,
+TaskAR::TaskAR(const ctor::build_configuration& config,
+ const ctor::settings& settings,
const std::string& target,
const std::vector<std::string>& objects,
- const std::string& sourcePath)
- : Task(config)
+ const std::string& sourceDir)
+ : Task(config, settings, sourceDir)
, config(config)
, settings(settings)
+ , sourceDir(sourceDir)
{
- std::filesystem::path base = settings.builddir;
- base /= sourcePath;
- std::filesystem::create_directories(base);
+ std::filesystem::create_directories(std::filesystem::path(settings.builddir) / sourceDir);
- targetFile = base / target;
+ _targetFile = target;
for(const auto& object : objects)
{
std::filesystem::path objectFile = object;
@@ -34,30 +33,28 @@ TaskAR::TaskAR(const BuildConfiguration& config,
for(const auto& dep : config.depends)
{
- std::filesystem::path depFile = settings.builddir;
- depFile /= dep;
- depFiles.push_back(depFile);
+ depFiles.push_back(dep);
}
- flagsFile = base / targetFile.stem();
+ flagsFile = std::filesystem::path(settings.builddir) / cleanUp(sourceDir) / targetFile().stem();
flagsFile += ".flags";
- target_type = TargetType::StaticLibrary;
- source_language = Language::C;
+ target_type = ctor::target_type::static_library;
+ source_language = ctor::language::c;
for(const auto& source : config.sources)
{
std::filesystem::path sourceFile(source.file);
// TODO: Use task languages instead
if(sourceFile.extension().string() != ".c")
{
- source_language = Language::Cpp;
+ source_language = ctor::language::cpp;
}
}
}
bool TaskAR::dirtyInner()
{
- if(!std::filesystem::exists(targetFile))
+ if(!std::filesystem::exists(targetFile()))
{
return true;
}
@@ -67,15 +64,6 @@ bool TaskAR::dirtyInner()
return true;
}
- for(const auto& objectFile : objectFiles)
- {
- if(std::filesystem::last_write_time(targetFile) <=
- std::filesystem::last_write_time(objectFile))
- {
- return true;
- }
- }
-
{
auto lastFlags = readFile(flagsFile.string());
if(flagsString() != lastFlags)
@@ -90,22 +78,16 @@ bool TaskAR::dirtyInner()
int TaskAR::runInner()
{
- std::string objectlist;
- for(const auto& objectFile : objectFiles)
- {
- if(!objectlist.empty())
- {
- objectlist += " ";
- }
- objectlist += objectFile.string();
- }
+ auto toolchain = getToolChain(config.system);
std::vector<std::string> args;
- args.push_back("rcs");
- args.push_back(targetFile.string());
- for(const auto& objectFile : objectFiles)
+ append(args, ar_option(toolchain, ctor::ar_opt::replace));
+ append(args, ar_option(toolchain, ctor::ar_opt::add_index));
+ append(args, ar_option(toolchain, ctor::ar_opt::create));
+ append(args, ar_option(toolchain, ctor::ar_opt::output, targetFile().string()));
+ for(const auto& task : getDependsTasks())
{
- args.push_back(objectFile.string());
+ args.push_back(task->targetFile().string());
}
{ // Write flags to file.
@@ -115,17 +97,18 @@ int TaskAR::runInner()
if(settings.verbose == 0)
{
- std::cout << "AR => " << targetFile.string() << "\n";
+ std::cout << "AR => " << targetFile().string() << std::endl;
}
+ const auto& c = ctor::get_configuration();
std::string tool;
switch(outputSystem())
{
- case OutputSystem::Host:
- tool = getConfiguration(cfg::host_ar, "/usr/bin/ar");
+ case ctor::output_system::host:
+ tool = c.get(ctor::cfg::host_ar, "/usr/bin/ar");
break;
- case OutputSystem::Build:
- tool = getConfiguration(cfg::build_ar, "/usr/bin/ar");
+ case ctor::output_system::build:
+ tool = c.get(ctor::cfg::build_ar, "/usr/bin/ar");
break;
}
@@ -134,10 +117,10 @@ int TaskAR::runInner()
int TaskAR::clean()
{
- if(std::filesystem::exists(targetFile))
+ if(std::filesystem::exists(targetFile()))
{
- std::cout << "Removing " << targetFile.string() << "\n";
- std::filesystem::remove(targetFile);
+ std::cout << "Removing " << targetFile().string() << "\n";
+ std::filesystem::remove(targetFile());
}
if(std::filesystem::exists(flagsFile))
@@ -157,9 +140,9 @@ std::vector<std::string> TaskAR::depends() const
deps.push_back(objectFile.string());
}
- for(const auto& depFile : depFiles)
+ for(const auto& dep : config.depends)
{
- deps.push_back(depFile.string());
+ deps.push_back(dep);
}
return deps;
@@ -167,7 +150,12 @@ std::vector<std::string> TaskAR::depends() const
std::string TaskAR::target() const
{
- return targetFile.string();
+ return _targetFile.string();
+}
+
+std::filesystem::path TaskAR::targetFile() const
+{
+ return std::filesystem::path(settings.builddir) / sourceDir / _targetFile;
}
bool TaskAR::derived() const
@@ -177,14 +165,20 @@ bool TaskAR::derived() const
std::string TaskAR::flagsString() const
{
+ auto toolchain = getToolChain(config.system);
std::string flagsStr;
+ bool first{true};
for(const auto& flag : config.flags.ldflags)
{
- if(flag != config.flags.ldflags[0])
+ for(const auto& str : to_strings(toolchain, flag))
{
- flagsStr += " ";
+ if(first)
+ {
+ flagsStr += " ";
+ first = false;
+ }
+ flagsStr += str;
}
- flagsStr += flag;
}
flagsStr += "\n";
diff --git a/src/task_ar.h b/src/task_ar.h
index f540fef..601afeb 100644
--- a/src/task_ar.h
+++ b/src/task_ar.h
@@ -10,18 +10,16 @@
#include <future>
#include <filesystem>
-struct BuildConfiguration;
-struct Settings;
-
class TaskAR
: public Task
{
public:
- TaskAR(const BuildConfiguration& config,
- const Settings& settings,
+ TaskAR(const ctor::build_configuration& config,
+ const ctor::settings& settings,
const std::string& target,
const std::vector<std::string>& objects,
- const std::string& sourcePath);
+ const std::string& sourceDir);
+ virtual ~TaskAR() = default;
bool dirtyInner() override;
@@ -31,6 +29,8 @@ public:
std::vector<std::string> depends() const override;
std::string target() const override;
+ std::filesystem::path targetFile() const override;
+
bool derived() const override;
private:
@@ -38,9 +38,10 @@ private:
std::vector<std::filesystem::path> objectFiles;
std::vector<std::filesystem::path> depFiles;
- std::filesystem::path targetFile;
+ std::filesystem::path _targetFile;
std::filesystem::path flagsFile;
- const BuildConfiguration& config;
- const Settings& settings;
+ const ctor::build_configuration& config;
+ const ctor::settings& settings;
+ std::string sourceDir;
};
diff --git a/src/task_cc.cc b/src/task_cc.cc
index 1db9767..56915f5 100644
--- a/src/task_cc.cc
+++ b/src/task_cc.cc
@@ -7,88 +7,83 @@
#include <fstream>
#include <cassert>
-#include "libctor.h"
-#include "settings.h"
+#include "ctor.h"
#include "execute.h"
#include "util.h"
+#include "tools.h"
-namespace
-{
-bool isClean(char c)
-{
- return c != '.' && c != '/';
-}
-
-std::string cleanUp(const std::string& path)
-{
- std::string cleaned;
- for(const auto& c : path)
- {
- if(isClean(c))
- {
- cleaned += c;
- }
- else
- {
- cleaned += '_';
- }
- }
- return cleaned;
-}
-}
-
-TaskCC::TaskCC(const BuildConfiguration& config, const Settings& settings,
- const std::string& sourceDir, const Source& source)
- : Task(config)
+TaskCC::TaskCC(const ctor::build_configuration& config, const ctor::settings& settings,
+ const std::string& sourceDir, const ctor::source& source)
+ : Task(config, settings, sourceDir)
, config(config)
, settings(settings)
, sourceDir(sourceDir)
+ , _source(source)
{
sourceFile = sourceDir;
sourceFile /= source.file;
- std::filesystem::path base = settings.builddir;
- base /= sourceFile.parent_path();
- std::filesystem::create_directories(base);
+ std::filesystem::path base = sourceFile.parent_path();
+ std::filesystem::create_directories(std::filesystem::path(settings.builddir) / base);
base /= cleanUp(config.target);
base += "-";
base += sourceFile.stem();
- target_type = TargetType::Object;
+ target_type = ctor::target_type::object;
source_language = source.language;
- if(source_language == Language::Auto)
+ if(source_language == ctor::language::automatic)
{
source_language = languageFromExtension(sourceFile);
}
switch(source_language)
{
- case Language::C:
+ case ctor::language::c:
base += "_c";
break;
- case Language::Cpp:
+ case ctor::language::cpp:
base += "_cc";
break;
- case Language::Asm:
+ case ctor::language::assembler:
base += "_asm";
break;
- case Language::Auto:
+ case ctor::language::automatic:
assert(0 && "This should never happen");
break;
}
- targetFile = base;
- targetFile += ".o";
- depsFile = base;
+ if(source.output.empty())
+ {
+ _targetFile = base;
+ _targetFile += ".o";
+ }
+ else
+ {
+ _targetFile = source.output;
+ }
+ depsFile = targetFile().parent_path() / targetFile().stem();
depsFile += ".d";
- flagsFile = base;
+ flagsFile = targetFile().parent_path() / targetFile().stem();
flagsFile += ".flags";
}
+int TaskCC::registerDepTasksInner(const std::set<std::shared_ptr<Task>>& tasks)
+{
+ for(const auto& task : tasks)
+ {
+ if(*task == _source.file)
+ {
+ dependsTasks.insert(task);
+ }
+ }
+
+ return 0;
+}
+
std::string TaskCC::name() const
{
- return target();
+ return {};
}
bool TaskCC::dirtyInner()
@@ -99,7 +94,7 @@ bool TaskCC::dirtyInner()
return true;
}
- if(!std::filesystem::exists(targetFile))
+ if(!std::filesystem::exists(targetFile()))
{
//std::cout << "Missing targetFile\n";
return true;
@@ -137,7 +132,7 @@ bool TaskCC::dirtyInner()
for(const auto& dep : depList)
{
if(!std::filesystem::exists(dep) ||
- std::filesystem::last_write_time(targetFile) <
+ std::filesystem::last_write_time(targetFile()) <
std::filesystem::last_write_time(dep))
{
//std::cout << "The targetFile older than " << std::string(dep) << "\n";
@@ -146,7 +141,7 @@ bool TaskCC::dirtyInner()
}
if(std::filesystem::last_write_time(sourceFile) >
- std::filesystem::last_write_time(targetFile))
+ std::filesystem::last_write_time(targetFile()))
{
//std::cout << "The targetFile older than sourceFile\n";
return true;
@@ -172,9 +167,22 @@ int TaskCC::runInner()
if(settings.verbose == 0)
{
- std::cout << compiler() << " " <<
+ switch(sourceLanguage())
+ {
+ case ctor::language::c:
+ std::cout << "CC ";
+ break;
+ case ctor::language::cpp:
+ std::cout << "CXX ";
+ break;
+ case ctor::language::automatic:
+ case ctor::language::assembler:
+ // Only c/c++ handled by this task type.
+ break;
+ }
+ std::cout <<
sourceFile.lexically_normal().string() << " => " <<
- targetFile.lexically_normal().string() << "\n";
+ targetFile().lexically_normal().string() << std::endl;
}
return execute(compiler(), args, settings.verbose > 0);
@@ -182,10 +190,10 @@ int TaskCC::runInner()
int TaskCC::clean()
{
- if(std::filesystem::exists(targetFile))
+ if(std::filesystem::exists(targetFile()))
{
- std::cout << "Removing " << targetFile.string() << "\n";
- std::filesystem::remove(targetFile);
+ std::cout << "Removing " << targetFile().string() << "\n";
+ std::filesystem::remove(targetFile());
}
if(std::filesystem::exists(depsFile))
@@ -210,7 +218,12 @@ std::vector<std::string> TaskCC::depends() const
std::string TaskCC::target() const
{
- return targetFile.string();
+ return _targetFile.string();
+}
+
+std::filesystem::path TaskCC::targetFile() const
+{
+ return std::filesystem::path(settings.builddir) / _targetFile;
}
bool TaskCC::derived() const
@@ -224,7 +237,7 @@ std::string TaskCC::toJSON() const
json += "\t{\n";
json += "\t\t\"directory\": \"" + sourceDir.string() + "\",\n";
json += "\t\t\"file\": \"" + sourceFile.lexically_normal().string() + "\",\n";
- json += "\t\t\"output\": \"" + targetFile.string() + "\",\n";
+ json += "\t\t\"output\": \"" + targetFile().string() + "\",\n";
json += "\t\t\"arguments\": [ \"" + compiler() + "\"";
auto args = getCompilerArgs();
for(const auto& arg : args)
@@ -243,12 +256,23 @@ std::string TaskCC::source() const
std::vector<std::string> TaskCC::flags() const
{
+ std::vector<std::string> flags;
+ auto toolchain = getToolChain(config.system);
+
switch(sourceLanguage())
{
- case Language::C:
- return config.flags.cflags;
- case Language::Cpp:
- return config.flags.cxxflags;
+ case ctor::language::c:
+ for(const auto& flag : config.flags.cflags)
+ {
+ append(flags, to_strings(toolchain, flag));
+ }
+ return flags;
+ case ctor::language::cpp:
+ for(const auto& flag : config.flags.cxxflags)
+ {
+ append(flags, to_strings(toolchain, flag));
+ }
+ return flags;
default:
std::cerr << "Unknown CC target type\n";
exit(1);
@@ -268,42 +292,100 @@ std::string TaskCC::flagsString() const
std::vector<std::string> TaskCC::getCompilerArgs() const
{
+ auto toolchain = getToolChain(config.system);
auto compiler_flags = flags();
std::vector<std::string> args;
- args.push_back("-MMD");
- if(std::filesystem::path(config.target).extension() == ".so")
+ switch(sourceLanguage())
{
- // Add -fPIC arg to all contained object files
- args.push_back("-fPIC");
- }
+ case ctor::language::c:
+ {
+ append(args, c_option(toolchain, ctor::c_opt::generate_dep_tree));
- args.push_back("-c");
- args.push_back(sourceFile.string());
- args.push_back("-o");
- args.push_back(targetFile.string());
+ if(std::filesystem::path(config.target).extension() == ".so")
+ {
+ // Add -fPIC arg to all contained object files
+ append(args, c_option(toolchain,
+ ctor::c_opt::position_independent_code));
+ }
- for(const auto& flag : compiler_flags)
- {
- // Is arg an added include path?
- if(flag.substr(0, 2) == "-I")
+ append(args, c_option(toolchain, ctor::c_opt::no_link));
+ args.push_back(sourceFile.string());
+ append(args, c_option(toolchain,
+ ctor::c_opt::output, targetFile().string()));
+
+ // Relative include paths has to be altered to be relative to sourceDir
+ for(const auto& flag : compiler_flags)
+ {
+ auto option = c_option(flag, toolchain);
+ switch(option.opt)
+ {
+ case ctor::c_opt::include_path:
+ {
+ std::filesystem::path path(option.arg);
+ if(path.is_relative())
+ {
+ path = (sourceDir / path).lexically_normal();
+ append(args, c_option(toolchain,
+ ctor::c_opt::include_path, path.string()));
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ args.push_back(flag);
+ }
+ }
+ break;
+
+ case ctor::language::cpp:
{
- std::string include_path = flag.substr(2);
- include_path.erase(0, include_path.find_first_not_of(' '));
- std::filesystem::path path(include_path);
+ append(args, cxx_option(toolchain, ctor::cxx_opt::generate_dep_tree));
+
+ if(std::filesystem::path(config.target).extension() == ".so")
+ {
+ // Add -fPIC arg to all contained object files
+ append(args, cxx_option(toolchain,
+ ctor::cxx_opt::position_independent_code));
+ }
- // Is it relative?
- if(path.is_relative())
+ append(args, cxx_option(toolchain, ctor::cxx_opt::no_link));
+ args.push_back(sourceFile.string());
+ append(args, cxx_option(toolchain,
+ ctor::cxx_opt::output, targetFile().string()));
+
+ // Relative include paths has to be altered to be relative to sourceDir
+ for(const auto& flag : compiler_flags)
{
- path = (sourceDir / path).lexically_normal();
- std::string new_include_path = "-I" + path.string();
- args.push_back(new_include_path);
- continue;
+ auto option = cxx_option(flag, toolchain);
+ switch(option.opt)
+ {
+ case ctor::cxx_opt::include_path:
+ {
+ std::filesystem::path path(option.arg);
+ if(path.is_relative())
+ {
+ path = (sourceDir / path).lexically_normal();
+ append(args, cxx_option(toolchain,
+ ctor::cxx_opt::include_path, path.string()));
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ args.push_back(flag);
}
+
}
+ break;
- args.push_back(flag);
+ default:
+ break;
}
return args;
diff --git a/src/task_cc.h b/src/task_cc.h
index c309abd..70bb13c 100644
--- a/src/task_cc.h
+++ b/src/task_cc.h
@@ -10,16 +10,16 @@
#include <future>
#include <filesystem>
-struct BuildConfiguration;
-struct Settings;
-
class TaskCC
: public Task
{
public:
- TaskCC(const BuildConfiguration& config,
- const Settings& settings,
- const std::string& sourceDir, const Source& source);
+ TaskCC(const ctor::build_configuration& config,
+ const ctor::settings& settings,
+ const std::string& sourceDir, const ctor::source& source);
+ virtual ~TaskCC() = default;
+
+ int registerDepTasksInner(const std::set<std::shared_ptr<Task>>& tasks) override;
std::string name() const override;
bool dirtyInner() override;
@@ -30,6 +30,8 @@ public:
std::vector<std::string> depends() const override;
std::string target() const override;
+ std::filesystem::path targetFile() const override;
+
bool derived() const override;
std::string toJSON() const override;
@@ -42,11 +44,12 @@ protected:
std::vector<std::string> getCompilerArgs() const;
std::filesystem::path sourceFile;
- std::filesystem::path targetFile;
+ std::filesystem::path _targetFile;
std::filesystem::path depsFile;
std::filesystem::path flagsFile;
- const BuildConfiguration& config;
- const Settings& settings;
+ const ctor::build_configuration& config;
+ const ctor::settings& settings;
std::filesystem::path sourceDir;
+ const ctor::source& _source;
};
diff --git a/src/task_fn.cc b/src/task_fn.cc
new file mode 100644
index 0000000..b11ff15
--- /dev/null
+++ b/src/task_fn.cc
@@ -0,0 +1,121 @@
+// -*- c++ -*-
+// Distributed under the BSD 2-Clause License.
+// See accompanying file LICENSE for details.
+#include "task_fn.h"
+
+#include <iostream>
+#include <fstream>
+#include <cassert>
+
+#include "ctor.h"
+#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)
+ : Task(config, settings, sourceDir)
+ , config(config)
+ , settings(settings)
+{
+ sourceFile = sourceDir;
+ sourceFile /= source.file;
+
+ std::filesystem::create_directories(std::filesystem::path(settings.builddir) / sourceFile.parent_path());
+
+ target_type = config.type;
+ source_language = source.language;
+
+ if(source.output.empty())
+ {
+ std::cerr << "Missing output file for functional target\n";
+ exit(1);
+ }
+
+ _targetFile = source.output;
+}
+
+bool TaskFn::dirtyInner()
+{
+ if(!std::filesystem::exists(sourceFile))
+ {
+ //std::cout << "Missing source file: " << std::string(sourceFile) << "\n";
+ return true;
+ }
+
+ if(!std::filesystem::exists(targetFile()))
+ {
+ //std::cout << "Missing targetFile\n";
+ return true;
+ }
+
+ if(std::filesystem::last_write_time(sourceFile) >
+ std::filesystem::last_write_time(targetFile()))
+ {
+ //std::cout << "The targetFile older than sourceFile\n";
+ return true;
+ }
+
+ return false;
+}
+
+int TaskFn::runInner()
+{
+ if(!std::filesystem::exists(sourceFile))
+ {
+ std::cout << "Missing source file: " << sourceFile.string() << "\n";
+ return 1;
+ }
+
+ if(settings.verbose >= 0)
+ {
+ std::cout << "Fn" << " " <<
+ sourceFile.lexically_normal().string() << " => " <<
+ targetFile().lexically_normal().string() << std::endl;
+ }
+
+ return config.function(sourceFile.string(),
+ targetFile().string(),
+ config,
+ settings);
+}
+
+int TaskFn::clean()
+{
+ if(std::filesystem::exists(targetFile()))
+ {
+ std::cout << "Removing " << targetFile().string() << "\n";
+ std::filesystem::remove(targetFile());
+ }
+
+ return 0;
+}
+
+std::vector<std::string> TaskFn::depends() const
+{
+ return {};
+}
+
+std::string TaskFn::target() const
+{
+ return _targetFile;
+}
+
+std::filesystem::path TaskFn::targetFile() const
+{
+ return std::filesystem::path(settings.builddir) / sourceDir / _targetFile;
+}
+
+bool TaskFn::derived() const
+{
+ return false;
+}
+
+std::string TaskFn::toJSON() const
+{
+ return {}; // TODO: Not sure how to express this...
+}
+
+std::string TaskFn::source() const
+{
+ return sourceFile.string();
+}
diff --git a/src/task_fn.h b/src/task_fn.h
new file mode 100644
index 0000000..1bad32c
--- /dev/null
+++ b/src/task_fn.h
@@ -0,0 +1,44 @@
+// -*- c++ -*-
+// Distributed under the BSD 2-Clause License.
+// See accompanying file LICENSE for details.
+#pragma once
+
+#include "task.h"
+
+#include <vector>
+#include <string>
+#include <future>
+#include <filesystem>
+
+class TaskFn
+ : public Task
+{
+public:
+ TaskFn(const ctor::build_configuration& config,
+ const ctor::settings& settings,
+ const std::string& sourceDir, const ctor::source& source);
+ virtual ~TaskFn() = default;
+
+ bool dirtyInner() override;
+
+ int runInner() override;
+ int clean() override;
+
+ std::vector<std::string> depends() const override;
+
+ std::string target() const override;
+ std::filesystem::path targetFile() const override;
+ bool derived() const override;
+
+ std::string toJSON() const override;
+
+ std::string source() const override;
+
+protected:
+ std::filesystem::path sourceFile;
+ std::filesystem::path _targetFile;
+
+ const ctor::build_configuration& config;
+ const ctor::settings& settings;
+ std::filesystem::path sourceDir;
+};
diff --git a/src/task_ld.cc b/src/task_ld.cc
index 82c26a9..3d917e4 100644
--- a/src/task_ld.cc
+++ b/src/task_ld.cc
@@ -6,46 +6,30 @@
#include <iostream>
#include <fstream>
-#include "libctor.h"
-#include "settings.h"
+#include "ctor.h"
#include "execute.h"
+#include "util.h"
+#include "tools.h"
-namespace
-{
-std::string readFile(const std::string &fileName)
-{
- std::ifstream ifs(fileName.c_str(), std::ios::in | std::ios::binary | std::ios::ate);
-
- std::ifstream::pos_type fileSize = ifs.tellg();
- ifs.seekg(0, std::ios::beg);
-
- std::vector<char> bytes(fileSize);
- ifs.read(bytes.data(), fileSize);
-
- return std::string(bytes.data(), fileSize);
-}
-} // namespace ::
-
-TaskLD::TaskLD(const BuildConfiguration& config,
- const Settings& settings,
+TaskLD::TaskLD(const ctor::build_configuration& config,
+ const ctor::settings& settings,
const std::string& target,
const std::vector<std::string>& objects,
- const std::string& sourcePath)
- : Task(config)
+ const std::string& sourceDir)
+ : Task(config, settings, sourceDir)
, config(config)
, settings(settings)
+ , sourceDir(sourceDir)
{
target_type = config.type;
- if(target_type == TargetType::Auto)
+ if(target_type == ctor::target_type::automatic)
{
- target_type = TargetType::Executable;
+ target_type = ctor::target_type::executable;
}
- std::filesystem::path base = settings.builddir;
- base /= sourcePath;
- std::filesystem::create_directories(base);
+ std::filesystem::create_directories(std::filesystem::path(settings.builddir) / sourceDir);
- targetFile = base / target;
+ _targetFile = target;
for(const auto& object : objects)
{
std::filesystem::path objectFile = object;
@@ -55,28 +39,26 @@ TaskLD::TaskLD(const BuildConfiguration& config,
for(const auto& dep : config.depends)
{
- std::filesystem::path depFile = settings.builddir;
- depFile /= dep;
- depFiles.push_back(depFile);
+ depFiles.push_back(dep);
}
- flagsFile = base / targetFile.stem();
+ flagsFile = std::filesystem::path(settings.builddir) / cleanUp(sourceDir) / targetFile().stem();
flagsFile += ".flags";
- source_language = Language::C;
+ source_language = ctor::language::c;
for(const auto& source : config.sources)
{
std::filesystem::path sourceFile(source.file);
if(sourceFile.extension().string() != ".c")
{
- source_language = Language::Cpp;
+ source_language = ctor::language::cpp;
}
}
}
bool TaskLD::dirtyInner()
{
- if(!std::filesystem::exists(targetFile))
+ if(!std::filesystem::exists(targetFile()))
{
return true;
}
@@ -86,15 +68,6 @@ bool TaskLD::dirtyInner()
return true;
}
- for(const auto& objectFile : objectFiles)
- {
- if(std::filesystem::last_write_time(targetFile) <=
- std::filesystem::last_write_time(objectFile))
- {
- return true;
- }
- }
-
{
auto lastFlags = readFile(flagsFile.string());
if(flagsString() != lastFlags)
@@ -109,31 +82,20 @@ bool TaskLD::dirtyInner()
int TaskLD::runInner()
{
- std::string objectlist;
- for(const auto& objectFile : objectFiles)
- {
- if(!objectlist.empty())
- {
- objectlist += " ";
- }
- objectlist += objectFile.string();
- }
+ auto toolchain = getToolChain(config.system);
std::vector<std::string> args;
- for(const auto& objectFile : objectFiles)
- {
- args.push_back(objectFile.string());
- }
-
- for(const auto& depFile : depFiles)
+ for(const auto& dep : getDependsTasks())
{
+ auto depFile = dep->targetFile();
if(depFile.extension() == ".so")
{
- args.push_back(std::string("-L") + settings.builddir);
+ append(args, ld_option(toolchain, ctor::ld_opt::library_path,
+ targetFile().parent_path().string()));
auto lib = depFile.stem().string().substr(3); // strip 'lib' prefix
- args.push_back(std::string("-l") + lib);
+ append(args, ld_option(toolchain, ctor::ld_opt::link, lib));
}
- else if(depFile.extension() == ".a")
+ else if(depFile.extension() == ".a" || depFile.extension() == ".o")
{
args.push_back(depFile.string());
}
@@ -141,10 +103,10 @@ int TaskLD::runInner()
for(const auto& flag : config.flags.ldflags)
{
- args.push_back(flag);
+ append(args, to_strings(toolchain, flag));
}
- args.push_back("-o");
- args.push_back(targetFile.string());
+
+ append(args, ld_option(toolchain, ctor::ld_opt::output, targetFile().string()));
{ // Write flags to file.
std::ofstream flagsStream(flagsFile);
@@ -153,7 +115,7 @@ int TaskLD::runInner()
if(settings.verbose == 0)
{
- std::cout << "LD => " << targetFile.string() << "\n";
+ std::cout << "LD => " << targetFile().string() << std::endl;
}
auto tool = compiler();
@@ -162,10 +124,10 @@ int TaskLD::runInner()
int TaskLD::clean()
{
- if(std::filesystem::exists(targetFile))
+ if(std::filesystem::exists(targetFile()))
{
- std::cout << "Removing " << targetFile.string() << "\n";
- std::filesystem::remove(targetFile);
+ std::cout << "Removing " << targetFile().string() << "\n";
+ std::filesystem::remove(targetFile());
}
if(std::filesystem::exists(flagsFile))
@@ -195,7 +157,12 @@ std::vector<std::string> TaskLD::depends() const
std::string TaskLD::target() const
{
- return targetFile.string();
+ return _targetFile.string();
+}
+
+std::filesystem::path TaskLD::targetFile() const
+{
+ return std::filesystem::path(settings.builddir) / sourceDir / _targetFile;
}
bool TaskLD::derived() const
@@ -205,14 +172,20 @@ bool TaskLD::derived() const
std::string TaskLD::flagsString() const
{
+ auto toolchain = getToolChain(config.system);
std::string flagsStr;
+ bool first{true};
for(const auto& flag : config.flags.ldflags)
{
- if(flag != config.flags.ldflags[0])
+ for(const auto& str : to_strings(toolchain, flag))
{
- flagsStr += " ";
+ if(first)
+ {
+ flagsStr += " ";
+ first = false;
+ }
+ flagsStr += str;
}
- flagsStr += flag;
}
flagsStr += "\n";
diff --git a/src/task_ld.h b/src/task_ld.h
index 516641f..dbe7db1 100644
--- a/src/task_ld.h
+++ b/src/task_ld.h
@@ -10,18 +10,16 @@
#include <future>
#include <filesystem>
-struct BuildConfiguration;
-struct Settings;
-
class TaskLD
: public Task
{
public:
- TaskLD(const BuildConfiguration& config,
- const Settings& settings,
+ TaskLD(const ctor::build_configuration& config,
+ const ctor::settings& settings,
const std::string& target,
const std::vector<std::string>& objects,
- const std::string& sourcePath);
+ const std::string& _sourceDir);
+ virtual ~TaskLD() = default;
bool dirtyInner() override;
@@ -31,6 +29,8 @@ public:
std::vector<std::string> depends() const override;
std::string target() const override;
+ std::filesystem::path targetFile() const override;
+
bool derived() const override;
private:
@@ -38,9 +38,10 @@ private:
std::vector<std::filesystem::path> objectFiles;
std::vector<std::filesystem::path> depFiles;
- std::filesystem::path targetFile;
+ std::filesystem::path _targetFile;
std::filesystem::path flagsFile;
- const BuildConfiguration& config;
- const Settings& settings;
+ const ctor::build_configuration& config;
+ const ctor::settings& settings;
+ std::string sourceDir;
};
diff --git a/src/task_so.cc b/src/task_so.cc
index bf47e05..9061591 100644
--- a/src/task_so.cc
+++ b/src/task_so.cc
@@ -6,25 +6,25 @@
#include <iostream>
#include <fstream>
-#include "libctor.h"
-#include "settings.h"
+#include "ctor.h"
#include "execute.h"
#include "util.h"
+#include "tools.h"
-TaskSO::TaskSO(const BuildConfiguration& config,
- const Settings& settings,
+TaskSO::TaskSO(const ctor::build_configuration& config,
+ const ctor::settings& settings,
const std::string& target,
const std::vector<std::string>& objects,
- const std::string& sourcePath)
- : Task(config)
+ const std::string& sourceDir)
+ : Task(config, settings, sourceDir)
, config(config)
, settings(settings)
+ , sourceDir(sourceDir)
{
- std::filesystem::path base = settings.builddir;
- base /= sourcePath;
- std::filesystem::create_directories(base);
+ std::filesystem::path base = sourceDir;
+ std::filesystem::create_directories(std::filesystem::path(settings.builddir) / base);
- targetFile = base / target;
+ _targetFile = base / target;
for(const auto& object : objects)
{
std::filesystem::path objectFile = object;
@@ -34,30 +34,28 @@ TaskSO::TaskSO(const BuildConfiguration& config,
for(const auto& dep : config.depends)
{
- std::filesystem::path depFile = settings.builddir;
- depFile /= dep;
- depFiles.push_back(depFile);
+ depFiles.push_back(dep);
}
- flagsFile = base / targetFile.stem();
+ flagsFile = std::filesystem::path(settings.builddir) / cleanUp(sourceDir) / targetFile().stem();
flagsFile += ".flags";
- target_type = TargetType::DynamicLibrary;
- source_language = Language::C;
+ target_type = ctor::target_type::dynamic_library;
+ source_language = ctor::language::c;
for(const auto& source : config.sources)
{
std::filesystem::path sourceFile(source.file);
// TODO: Use task languages instead
if(sourceFile.extension().string() != ".c")
{
- source_language = Language::Cpp;
+ source_language = ctor::language::cpp;
}
}
}
bool TaskSO::dirtyInner()
{
- if(!std::filesystem::exists(targetFile))
+ if(!std::filesystem::exists(targetFile()))
{
return true;
}
@@ -67,15 +65,6 @@ bool TaskSO::dirtyInner()
return true;
}
- for(const auto& objectFile : objectFiles)
- {
- if(std::filesystem::last_write_time(targetFile) <=
- std::filesystem::last_write_time(objectFile))
- {
- return true;
- }
- }
-
{
auto lastFlags = readFile(flagsFile.string());
if(flagsString() != lastFlags)
@@ -90,37 +79,23 @@ bool TaskSO::dirtyInner()
int TaskSO::runInner()
{
- std::string objectlist;
- for(const auto& objectFile : objectFiles)
- {
- if(!objectlist.empty())
- {
- objectlist += " ";
- }
- objectlist += objectFile.string();
- }
+ auto toolchain = getToolChain(config.system);
std::vector<std::string> args;
- args.push_back("-fPIC");
- args.push_back("-shared");
-
- args.push_back("-o");
- args.push_back(targetFile.string());
+ append(args, ld_option(toolchain, ctor::ld_opt::position_independent_code));
+ append(args, ld_option(toolchain, ctor::ld_opt::build_shared));
- for(const auto& objectFile : objectFiles)
- {
- args.push_back(objectFile.string());
- }
+ append(args, ld_option(toolchain, ctor::ld_opt::output, targetFile().string()));
- for(const auto& depFile : depFiles)
+ for(const auto& task : getDependsTasks())
{
- args.push_back(depFile.string());
+ args.push_back(task->targetFile().string());
}
for(const auto& flag : config.flags.ldflags)
{
- args.push_back(flag);
+ append(args, to_strings(toolchain, flag));
}
{ // Write flags to file.
@@ -130,7 +105,7 @@ int TaskSO::runInner()
if(settings.verbose == 0)
{
- std::cout << "LD => " << targetFile.string() << "\n";
+ std::cout << "LD => " << targetFile().string() << std::endl;
}
auto tool = compiler();
@@ -139,10 +114,10 @@ int TaskSO::runInner()
int TaskSO::clean()
{
- if(std::filesystem::exists(targetFile))
+ if(std::filesystem::exists(targetFile()))
{
- std::cout << "Removing " << targetFile.string() << "\n";
- std::filesystem::remove(targetFile);
+ std::cout << "Removing " << targetFile().string() << "\n";
+ std::filesystem::remove(targetFile());
}
if(std::filesystem::exists(flagsFile))
@@ -172,7 +147,12 @@ std::vector<std::string> TaskSO::depends() const
std::string TaskSO::target() const
{
- return targetFile.string();
+ return _targetFile.string();
+}
+
+std::filesystem::path TaskSO::targetFile() const
+{
+ return std::filesystem::path(settings.builddir) / sourceDir / _targetFile;
}
bool TaskSO::derived() const
@@ -182,10 +162,20 @@ bool TaskSO::derived() const
std::string TaskSO::flagsString() const
{
- std::string flagsStr = compiler();
+ auto toolchain = getToolChain(config.system);
+ std::string flagsStr;
+ bool first{true};
for(const auto& flag : config.flags.ldflags)
{
- flagsStr += " " + flag;
+ for(const auto& str : to_strings(toolchain, flag))
+ {
+ if(first)
+ {
+ flagsStr += " ";
+ first = false;
+ }
+ flagsStr += str;
+ }
}
flagsStr += "\n";
diff --git a/src/task_so.h b/src/task_so.h
index a249421..60af225 100644
--- a/src/task_so.h
+++ b/src/task_so.h
@@ -10,18 +10,16 @@
#include <future>
#include <filesystem>
-struct BuildConfiguration;
-struct Settings;
-
class TaskSO
: public Task
{
public:
- TaskSO(const BuildConfiguration& config,
- const Settings& settings,
+ TaskSO(const ctor::build_configuration& config,
+ const ctor::settings& settings,
const std::string& target,
const std::vector<std::string>& objects,
- const std::string& sourcePath);
+ const std::string& sourceDir);
+ virtual ~TaskSO() = default;
bool dirtyInner() override;
@@ -31,6 +29,8 @@ public:
std::vector<std::string> depends() const override;
std::string target() const override;
+ std::filesystem::path targetFile() const override;
+
bool derived() const override;
private:
@@ -38,9 +38,10 @@ private:
std::vector<std::filesystem::path> objectFiles;
std::vector<std::filesystem::path> depFiles;
- std::filesystem::path targetFile;
+ std::filesystem::path _targetFile;
std::filesystem::path flagsFile;
- const BuildConfiguration& config;
- const Settings& settings;
+ const ctor::build_configuration& config;
+ const ctor::settings& settings;
+ std::string sourceDir;
};
diff --git a/src/tasks.cc b/src/tasks.cc
index 8ab296f..67bed2b 100644
--- a/src/tasks.cc
+++ b/src/tasks.cc
@@ -5,27 +5,28 @@
#include <filesystem>
#include <deque>
+#include <list>
#include <iostream>
#include <algorithm>
-#include "settings.h"
-#include "libctor.h"
+#include "ctor.h"
#include "task.h"
#include "task_cc.h"
#include "task_ld.h"
#include "task_ar.h"
#include "task_so.h"
+#include "task_fn.h"
#include "rebuild.h"
#include "configure.h"
-const std::deque<Target>& getTargets(const Settings& settings,
+const std::deque<Target>& getTargets(const ctor::settings& settings,
bool resolve_externals)
{
static bool initialised{false};
static std::deque<Target> targets;
if(!initialised)
{
- const auto& externals = configuration().externals;
+ const auto& externals = ctor::get_configuration().externals;
for(std::size_t i = 0; i < numConfigFiles; ++i)
{
std::string path =
@@ -34,7 +35,7 @@ const std::deque<Target>& getTargets(const Settings& settings,
{
std::cout << configFiles[i].file << " in path " << path << "\n";
}
- auto configs = configFiles[i].cb();
+ auto configs = configFiles[i].cb(settings);
for(auto& config : configs)
{
if(resolve_externals)
@@ -76,26 +77,32 @@ const std::deque<Target>& getTargets(const Settings& settings,
return targets;
}
-std::list<std::shared_ptr<Task>> taskFactory(const BuildConfiguration& config,
- const Settings& settings,
- const std::string& sourceDir)
+std::set<std::shared_ptr<Task>> taskFactory(const ctor::build_configuration& config,
+ const ctor::settings& settings,
+ const std::string& sourceDir)
{
+ std::set<std::shared_ptr<Task>> tasks;
+
std::filesystem::path targetFile(config.target);
- TargetType target_type{config.type};
- if(target_type == TargetType::Auto)
+ ctor::target_type target_type{config.type};
+ if(target_type == ctor::target_type::automatic)
{
- if(targetFile.extension() == ".a")
+ if(config.function != nullptr)
+ {
+ target_type = ctor::target_type::function;
+ }
+ else if(targetFile.extension() == ".a")
{
- target_type = TargetType::StaticLibrary;
+ target_type = ctor::target_type::static_library;
}
else if(targetFile.extension() == ".so")
{
- target_type = TargetType::DynamicLibrary;
+ target_type = ctor::target_type::dynamic_library;
}
else if(targetFile.extension() == "")
{
- target_type = TargetType::Executable;
+ target_type = ctor::target_type::executable;
}
else
{
@@ -106,43 +113,58 @@ std::list<std::shared_ptr<Task>> taskFactory(const BuildConfiguration& config,
}
std::vector<std::string> objects;
- std::list<std::shared_ptr<Task>> tasks;
- for(const auto& file : config.sources)
+ if(target_type != ctor::target_type::function)
{
- tasks.emplace_back(std::make_shared<TaskCC>(config, settings,
- sourceDir, file));
- objects.push_back(tasks.back()->target());
+ for(const auto& file : config.sources)
+ {
+ auto task = std::make_shared<TaskCC>(config, settings, sourceDir, file);
+ tasks.insert(task);
+ objects.push_back(task->targetFile().string());
+ }
}
+#ifndef BOOTSTRAP
+ else
+ {
+ for(const auto& file : config.sources)
+ {
+ auto task = std::make_shared<TaskFn>(config, settings, sourceDir, file);
+ tasks.insert(task);
+ objects.push_back(task->target());
+ }
+ }
+#endif
switch(target_type)
{
- case TargetType::Auto:
+ case ctor::target_type::automatic:
// The target_type cannot be Auto
break;
- case TargetType::StaticLibrary:
- tasks.emplace_back(std::make_shared<TaskAR>(config, settings, config.target,
- objects, sourceDir));
+ case ctor::target_type::static_library:
+ case ctor::target_type::unit_test_library:
+ tasks.insert(std::make_shared<TaskAR>(config, settings, config.target,
+ objects, sourceDir));
break;
#ifndef BOOTSTRAP
- case TargetType::DynamicLibrary:
+ case ctor::target_type::dynamic_library:
// TODO: Use C++20 starts_with
if(targetFile.stem().string().substr(0, 3) != "lib")
{
std::cerr << "Dynamic library target must have 'lib' prefix\n";
exit(1);
}
- tasks.emplace_back(std::make_shared<TaskSO>(config, settings, config.target,
- objects, sourceDir));
+ tasks.insert(std::make_shared<TaskSO>(config, settings, config.target,
+ objects, sourceDir));
break;
- case TargetType::Executable:
- case TargetType::UnitTest:
- tasks.emplace_back(std::make_shared<TaskLD>(config, settings, config.target,
- objects, sourceDir));
+ case ctor::target_type::executable:
+ case ctor::target_type::unit_test:
+ tasks.insert(std::make_shared<TaskLD>(config, settings, config.target,
+ objects, sourceDir));
break;
- case TargetType::Object:
+ case ctor::target_type::object:
+ case ctor::target_type::function:
break;
#else
default:
@@ -153,8 +175,8 @@ std::list<std::shared_ptr<Task>> taskFactory(const BuildConfiguration& config,
return tasks;
}
-std::shared_ptr<Task> getNextTask(const std::list<std::shared_ptr<Task>>& allTasks,
- std::list<std::shared_ptr<Task>>& dirtyTasks)
+std::shared_ptr<Task> getNextTask(const std::set<std::shared_ptr<Task>>& allTasks,
+ std::set<std::shared_ptr<Task>>& dirtyTasks)
{
for(auto dirtyTask = dirtyTasks.begin();
dirtyTask != dirtyTasks.end();
@@ -172,12 +194,12 @@ std::shared_ptr<Task> getNextTask(const std::list<std::shared_ptr<Task>>& allTas
return nullptr;
}
-std::list<std::shared_ptr<Task>> getTasks(const Settings& settings,
- const std::vector<std::string> names,
- bool resolve_externals)
+std::set<std::shared_ptr<Task>> getTasks(const ctor::settings& settings,
+ const std::vector<std::string> names,
+ bool resolve_externals)
{
auto& targets = getTargets(settings, resolve_externals);
- std::list<std::shared_ptr<Task>> tasks;
+ std::set<std::shared_ptr<Task>> tasks;
for(const auto& target : targets)
{
if(names.empty() ||
@@ -185,7 +207,7 @@ std::list<std::shared_ptr<Task>> getTasks(const Settings& settings,
{
std::vector<std::string> objects;
auto t = taskFactory(target.config, settings, target.path);
- tasks.insert(tasks.end(), t.begin(), t.end());
+ tasks.insert(t.begin(), t.end());
}
}
diff --git a/src/tasks.h b/src/tasks.h
index f2a77d4..ed1bf60 100644
--- a/src/tasks.h
+++ b/src/tasks.h
@@ -4,40 +4,37 @@
#pragma once
#include <string>
-#include <list>
+#include <set>
#include <memory>
#include <deque>
#include "task.h"
-class BuildConfiguration;
-class Settings;
-
struct Target
{
- BuildConfiguration config;
+ ctor::build_configuration config;
std::string path;
};
//! Get list of all registered targets
-const std::deque<Target>& getTargets(const Settings& settings,
+const std::deque<Target>& getTargets(const ctor::settings& settings,
bool resolve_externals = true);
//! Returns next dirty task from the dirtyTasks list that has all its dependencies
//! fulfilled.
//! The returned task is removed from the dirty list.
//! Return nullptr if no dirty task is ready.
-std::shared_ptr<Task> getNextTask(const std::list<std::shared_ptr<Task>>& allTasks,
- std::list<std::shared_ptr<Task>>& dirtyTasks);
+std::shared_ptr<Task> getNextTask(const std::set<std::shared_ptr<Task>>& allTasks,
+ std::set<std::shared_ptr<Task>>& dirtyTasks);
//! Get list of tasks filtered by name including each of their direct
//! dependency tasks (ie. objects tasks from their sources).
-std::list<std::shared_ptr<Task>> getTasks(const Settings& settings,
- const std::vector<std::string> names = {},
- bool resolve_externals = true);
+std::set<std::shared_ptr<Task>> getTasks(const ctor::settings& settings,
+ const std::vector<std::string> names = {},
+ bool resolve_externals = true);
//! Generate list of targets from a single configuration, including the final
//! link target and all its objects files (if any).
-std::list<std::shared_ptr<Task>> taskFactory(const BuildConfiguration& config,
- const Settings& settings,
- const std::string& sourceDir);
+std::set<std::shared_ptr<Task>> taskFactory(const ctor::build_configuration& config,
+ const ctor::settings& settings,
+ const std::string& sourceDir);
diff --git a/src/tools.cc b/src/tools.cc
new file mode 100644
index 0000000..28d3903
--- /dev/null
+++ b/src/tools.cc
@@ -0,0 +1,648 @@
+// -*- c++ -*-
+// Distributed under the BSD 2-Clause License.
+// See accompanying file LICENSE for details.
+#include "tools.h"
+
+#include <filesystem>
+#include <iostream>
+#include <sstream>
+
+#include <cassert>
+
+std::ostream& operator<<(std::ostream& stream, const ctor::c_opt& opt)
+{
+ // Adding to this enum should also imply adding to the unit-tests below
+ switch(opt)
+ {
+ case ctor::c_opt::output: stream << "ctor::c_opt::output"; break;
+ case ctor::c_opt::debug: stream << "ctor::c_opt::debug"; break;
+ case ctor::c_opt::warn_all: stream << "ctor::c_opt::warn_all"; break;
+ case ctor::c_opt::warnings_as_errors: stream << "ctor::c_opt::warnings_as_errors"; break;
+ case ctor::c_opt::generate_dep_tree: stream << "ctor::c_opt::generate_dep_tree"; break;
+ case ctor::c_opt::no_link: stream << "ctor::c_opt::no_link"; break;
+ case ctor::c_opt::include_path: stream << "ctor::c_opt::include_path"; break;
+ case ctor::c_opt::c_std: stream << "ctor::c_opt::c_std"; break;
+ case ctor::c_opt::optimization: stream << "ctor::c_opt::optimization"; break;
+ case ctor::c_opt::position_independent_code: stream << "ctor::c_opt::position_independent_code"; break;
+ case ctor::c_opt::position_independent_executable: stream << "ctor::c_opt::position_independent_executable"; break;
+ case ctor::c_opt::custom: stream << "ctor::c_opt::custom"; break;
+ }
+
+ return stream;
+}
+
+std::ostream& operator<<(std::ostream& stream, const ctor::cxx_opt& opt)
+{
+ // Adding to this enum should also imply adding to the unit-tests below
+ switch(opt)
+ {
+ case ctor::cxx_opt::output: stream << "ctor::cxx_opt::output"; break;
+ case ctor::cxx_opt::debug: stream << "ctor::cxx_opt::debug"; break;
+ case ctor::cxx_opt::warn_all: stream << "ctor::cxx_opt::warn_all"; break;
+ case ctor::cxx_opt::warnings_as_errors: stream << "ctor::cxx_opt::warnings_as_errors"; break;
+ case ctor::cxx_opt::generate_dep_tree: stream << "ctor::cxx_opt::generate_dep_tree"; break;
+ case ctor::cxx_opt::no_link: stream << "ctor::cxx_opt::no_link"; break;
+ case ctor::cxx_opt::include_path: stream << "ctor::cxx_opt::include_path"; break;
+ case ctor::cxx_opt::cpp_std: stream << "ctor::cxx_opt::cpp_std"; break;
+ case ctor::cxx_opt::optimization: stream << "ctor::cxx_opt::optimization"; break;
+ case ctor::cxx_opt::position_independent_code: stream << "ctor::cxx_opt::position_independent_code"; break;
+ case ctor::cxx_opt::position_independent_executable: stream << "ctor::cxx_opt::position_independent_executable"; break;
+ case ctor::cxx_opt::custom: stream << "ctor::cxx_opt::custom"; break;
+ }
+
+ return stream;
+}
+
+std::ostream& operator<<(std::ostream& stream, const ctor::ld_opt& opt)
+{
+ // Adding to this enum should also imply adding to the unit-tests below
+ switch(opt)
+ {
+ case ctor::ld_opt::output: stream << "ctor::ld_opt::output"; break;
+ case ctor::ld_opt::strip: stream << "ctor::ld_opt::strip"; break;
+ case ctor::ld_opt::warn_all: stream << "ctor::ld_opt::warn_all"; break;
+ case ctor::ld_opt::warnings_as_errors: stream << "ctor::ld_opt::warnings_as_errors"; break;
+ case ctor::ld_opt::library_path: stream << "ctor::ld_opt::library_path"; break;
+ case ctor::ld_opt::link: stream << "ctor::ld_opt::link"; break;
+ case ctor::ld_opt::cpp_std: stream << "ctor::ld_opt::cpp_std"; break;
+ case ctor::ld_opt::build_shared: stream << "ctor::ld_opt::build_shared"; break;
+ case ctor::ld_opt::threads: stream << "ctor::ld_opt::threads"; break;
+ case ctor::ld_opt::position_independent_code: stream << "ctor::ld_opt::position_independent_code"; break;
+ case ctor::ld_opt::position_independent_executable: stream << "ctor::ld_opt::position_independent_executable"; break;
+ case ctor::ld_opt::custom: stream << "ctor::ld_opt::custom"; break;
+ }
+
+ return stream;
+}
+
+std::ostream& operator<<(std::ostream& stream, const ctor::ar_opt& opt)
+{
+ // Adding to this enum should also imply adding to the unit-tests below
+ switch(opt)
+ {
+ case ctor::ar_opt::replace: stream << "ctor::ar_opt::replace"; break;
+ case ctor::ar_opt::add_index: stream << "ctor::ar_opt::add_index"; break;
+ case ctor::ar_opt::create: stream << "ctor::ar_opt::create"; break;
+ case ctor::ar_opt::output: stream << "ctor::ar_opt::output"; break;
+ case ctor::ar_opt::custom: stream << "ctor::ar_opt::custom"; break;
+ }
+
+ return stream;
+}
+
+std::ostream& operator<<(std::ostream& stream, const ctor::asm_opt& opt)
+{
+ // Adding to this enum should also imply adding to the unit-tests below
+ switch(opt)
+ {
+ case ctor::asm_opt::custom: stream << "ctor::asm_opt::custom"; break;
+ }
+
+ return stream;
+}
+
+ctor::toolchain getToolChain(const std::string& compiler)
+{
+ std::filesystem::path cc(compiler);
+ auto cc_cmd = cc.stem().string();
+
+ // Note: "g++" is a substring of "clang++" so "clang++" must be tested first.
+ if(cc_cmd.find("clang++") != std::string::npos)
+ {
+ return ctor::toolchain::clang;
+ }
+ else if(cc_cmd.find("g++") != std::string::npos)
+ {
+ return ctor::toolchain::gcc;
+ }
+
+ std::cerr << "Unsupported output system.\n";
+ return ctor::toolchain::gcc;
+}
+
+ctor::toolchain getToolChain(ctor::output_system system)
+{
+ const auto& cfg = ctor::get_configuration();
+ if(system == ctor::output_system::host)
+ {
+ if(cfg.host_toolchain != ctor::toolchain::none)
+ {
+ return cfg.host_toolchain;
+ }
+ return getToolChain(cfg.get(ctor::cfg::host_cxx, "g++"));
+ }
+ else
+ {
+ if(cfg.build_toolchain != ctor::toolchain::none)
+ {
+ return cfg.build_toolchain;
+ }
+ return getToolChain(cfg.get(ctor::cfg::build_cxx, "g++"));
+ }
+}
+
+namespace gcc {
+ctor::c_flag c_option(const std::string& flag)
+{
+ if(flag.substr(0, 2) == "-I")
+ {
+ std::string path = flag.substr(2);
+ path.erase(0, path.find_first_not_of(' '));
+ return { ctor::c_opt::include_path, path };
+ }
+
+ return { ctor::c_opt::custom, flag };
+}
+
+ctor::cxx_flag cxx_option(const std::string& flag)
+{
+ if(flag.substr(0, 2) == "-I")
+ {
+ std::string path = flag.substr(2);
+ path.erase(0, path.find_first_not_of(' '));
+ return { ctor::cxx_opt::include_path, path };
+ }
+
+ return { ctor::cxx_opt::custom, flag };
+}
+
+ctor::ld_flag ld_option(const std::string& flag)
+{
+ if(flag.substr(0, 2) == "-L")
+ {
+ std::string path = flag.substr(2);
+ path.erase(0, path.find_first_not_of(' '));
+ return { ctor::ld_opt::library_path, path };
+ }
+
+ return { ctor::ld_opt::custom, flag };
+}
+
+ctor::ar_flag ar_option(const std::string& flag)
+{
+ return { ctor::ar_opt::custom, flag };
+}
+
+std::vector<std::string> cxx_option(ctor::cxx_opt opt, const std::string& arg)
+{
+ switch(opt)
+ {
+ case ctor::cxx_opt::output:
+ return {"-o", arg};
+ case ctor::cxx_opt::debug:
+ return {"-g"};
+ case ctor::cxx_opt::warn_all:
+ return {"-Wall"};
+ case ctor::cxx_opt::warnings_as_errors:
+ return {"-Werror"};
+ case ctor::cxx_opt::generate_dep_tree:
+ return {"-MMD"};
+ case ctor::cxx_opt::no_link:
+ return {"-c"};
+ case ctor::cxx_opt::include_path:
+ return {"-I" + arg};
+ case ctor::cxx_opt::cpp_std:
+ return {"-std=" + arg};
+ case ctor::cxx_opt::optimization:
+ return {"-O" + arg};
+ case ctor::cxx_opt::position_independent_code:
+ return {"-fPIC"};
+ case ctor::cxx_opt::position_independent_executable:
+ return {"-fPIE"};
+ case ctor::cxx_opt::custom:
+ return {arg};
+ }
+
+ std::cerr << "Unsupported compiler option.\n";
+ return {};
+}
+
+std::vector<std::string> c_option(ctor::c_opt opt, const std::string& arg)
+{
+ switch(opt)
+ {
+ case ctor::c_opt::output:
+ return {"-o", arg};
+ case ctor::c_opt::debug:
+ return {"-g"};
+ case ctor::c_opt::warn_all:
+ return {"-Wall"};
+ case ctor::c_opt::warnings_as_errors:
+ return {"-Werror"};
+ case ctor::c_opt::generate_dep_tree:
+ return {"-MMD"};
+ case ctor::c_opt::no_link:
+ return {"-c"};
+ case ctor::c_opt::include_path:
+ return {"-I" + arg};
+ case ctor::c_opt::c_std:
+ return {"-std=" + arg};
+ case ctor::c_opt::optimization:
+ return {"-O" + arg};
+ case ctor::c_opt::position_independent_code:
+ return {"-fPIC"};
+ case ctor::c_opt::position_independent_executable:
+ return {"-fPIE"};
+ case ctor::c_opt::custom:
+ return {arg};
+ }
+
+ std::cerr << "Unsupported compiler option.\n";
+ return {};
+}
+
+std::vector<std::string> ld_option(ctor::ld_opt opt, const std::string& arg)
+{
+ switch(opt)
+ {
+ case ctor::ld_opt::output:
+ return {"-o", arg};
+ case ctor::ld_opt::strip:
+ return {"-s"};
+ case ctor::ld_opt::warn_all:
+ return {"-Wall"};
+ case ctor::ld_opt::warnings_as_errors:
+ return {"-Werror"};
+ case ctor::ld_opt::library_path:
+ return {"-L" + arg};
+ case ctor::ld_opt::link:
+ return {"-l" + arg};
+ case ctor::ld_opt::cpp_std:
+ return {"-std=" + arg};
+ case ctor::ld_opt::build_shared:
+ return {"-shared"};
+ case ctor::ld_opt::threads:
+ return {"-pthread"};
+ case ctor::ld_opt::position_independent_code:
+ return {"-fPIC"};
+ case ctor::ld_opt::position_independent_executable:
+ return {"-fPIE"};
+ case ctor::ld_opt::custom:
+ return {arg};
+ }
+
+ std::cerr << "Unsupported compiler option.\n";
+ return {};
+}
+
+std::vector<std::string> ar_option(ctor::ar_opt opt, const std::string& arg)
+{
+ switch(opt)
+ {
+ case ctor::ar_opt::replace:
+ return {"-r"};
+ case ctor::ar_opt::add_index:
+ return {"-s"};
+ case ctor::ar_opt::create:
+ return {"-c"};
+ case ctor::ar_opt::output:
+ return {arg};
+ case ctor::ar_opt::custom:
+ return {arg};
+ }
+
+ std::cerr << "Unsupported compiler option.\n";
+ return {};
+}
+
+std::vector<std::string> asm_option(ctor::asm_opt opt, const std::string& arg)
+{
+ switch(opt)
+ {
+ case ctor::asm_opt::custom:
+ return {arg};
+ }
+
+ std::cerr << "Unsupported compiler option.\n";
+ return {};
+}
+} // gcc::
+
+
+std::vector<std::string> c_option(ctor::toolchain toolchain,
+ ctor::c_opt opt,
+ const std::string& arg)
+{
+ switch(toolchain)
+ {
+ case ctor::toolchain::gcc:
+ case ctor::toolchain::clang:
+ return gcc::c_option(opt, arg);
+ case ctor::toolchain::any:
+ {
+ std::ostringstream ss;
+ ss << "{" << opt;
+ if(!arg.empty())
+ {
+ ss << ", \"" << arg << "\"";
+ }
+ ss << "}";
+ return { ss.str() };
+ }
+ case ctor::toolchain::none:
+ break;
+ }
+
+ std::cerr << "Unsupported tool-chain.\n";
+ return {};
+}
+
+std::vector<std::string> cxx_option(ctor::toolchain toolchain,
+ ctor::cxx_opt opt,
+ const std::string& arg)
+{
+ switch(toolchain)
+ {
+ case ctor::toolchain::gcc:
+ case ctor::toolchain::clang:
+ return gcc::cxx_option(opt, arg);
+ case ctor::toolchain::any:
+ {
+ std::ostringstream ss;
+ ss << "{" << opt;
+ if(!arg.empty())
+ {
+ ss << ", \"" << arg << "\"";
+ }
+ ss << "}";
+ return { ss.str() };
+ }
+ case ctor::toolchain::none:
+ break;
+ }
+
+ std::cerr << "Unsupported tool-chain.\n";
+ return {};
+}
+
+std::vector<std::string> ld_option(ctor::toolchain toolchain,
+ ctor::ld_opt opt,
+ const std::string& arg)
+{
+ switch(toolchain)
+ {
+ case ctor::toolchain::gcc:
+ case ctor::toolchain::clang:
+ return gcc::ld_option(opt, arg);
+ case ctor::toolchain::any:
+ {
+ std::ostringstream ss;
+ ss << "{" << opt;
+ if(!arg.empty())
+ {
+ ss << ", \"" << arg << "\"";
+ }
+ ss << "}";
+ return { ss.str() };
+ }
+ case ctor::toolchain::none:
+ break;
+ }
+
+ std::cerr << "Unsupported tool-chain.\n";
+ return {};
+}
+
+std::vector<std::string> ar_option(ctor::toolchain toolchain,
+ ctor::ar_opt opt,
+ const std::string& arg)
+{
+ switch(toolchain)
+ {
+ case ctor::toolchain::gcc:
+ case ctor::toolchain::clang:
+ return gcc::ar_option(opt, arg);
+ case ctor::toolchain::any:
+ {
+ std::ostringstream ss;
+ ss << "{" << opt;
+ if(!arg.empty())
+ {
+ ss << ", \"" << arg << "\"";
+ }
+ ss << "}";
+ return { ss.str() };
+ }
+ case ctor::toolchain::none:
+ break;
+ }
+
+ std::cerr << "Unsupported tool-chain.\n";
+ return {};
+}
+
+std::vector<std::string> asm_option(ctor::toolchain toolchain,
+ ctor::asm_opt opt,
+ const std::string& arg)
+{
+ switch(toolchain)
+ {
+ case ctor::toolchain::gcc:
+ case ctor::toolchain::clang:
+ return gcc::asm_option(opt, arg);
+ case ctor::toolchain::any:
+ {
+ std::ostringstream ss;
+ ss << "{" << opt;
+ if(!arg.empty())
+ {
+ ss << ", \"" << arg << "\"";
+ }
+ ss << "}";
+ return { ss.str() };
+ }
+ case ctor::toolchain::none:
+ break;
+ }
+
+ std::cerr << "Unsupported tool-chain.\n";
+ return {};
+}
+
+
+ctor::c_flag c_option(const std::string& flag, ctor::toolchain toolchain)
+{
+ switch(toolchain)
+ {
+ case ctor::toolchain::gcc:
+ case ctor::toolchain::clang:
+ return gcc::c_option(flag);
+ case ctor::toolchain::any:
+ case ctor::toolchain::none:
+ break;
+ }
+
+ return { ctor::c_opt::custom, flag };
+}
+
+ctor::cxx_flag cxx_option(const std::string& flag, ctor::toolchain toolchain)
+{
+ switch(toolchain)
+ {
+ case ctor::toolchain::gcc:
+ case ctor::toolchain::clang:
+ return gcc::cxx_option(flag);
+ case ctor::toolchain::any:
+ case ctor::toolchain::none:
+ break;
+ }
+
+ return { ctor::cxx_opt::custom, flag };
+}
+
+ctor::ld_flag ld_option(const std::string& flag, ctor::toolchain toolchain)
+{
+ switch(toolchain)
+ {
+ case ctor::toolchain::gcc:
+ case ctor::toolchain::clang:
+ return gcc::ld_option(flag);
+ case ctor::toolchain::any:
+ case ctor::toolchain::none:
+ break;
+ }
+
+ return { ctor::ld_opt::custom, flag };
+}
+
+ctor::ar_flag ar_option(const std::string& flag, ctor::toolchain toolchain)
+{
+ switch(toolchain)
+ {
+ case ctor::toolchain::gcc:
+ case ctor::toolchain::clang:
+ return gcc::ar_option(flag);
+ case ctor::toolchain::any:
+ case ctor::toolchain::none:
+ break;
+ }
+
+ return { ctor::ar_opt::custom, flag };
+}
+
+ctor::asm_flag asm_option(const std::string& flag, ctor::toolchain toolchain)
+{
+ switch(toolchain)
+ {
+ case ctor::toolchain::gcc:
+ case ctor::toolchain::clang:
+ case ctor::toolchain::any:
+ case ctor::toolchain::none:
+ break;
+ }
+
+ return { ctor::asm_opt::custom, flag };
+}
+
+// Flag to string coversions
+
+std::vector<std::string> to_strings(ctor::toolchain toolchain,
+ const ctor::c_flag& flag)
+{
+ if(flag.toolchain == ctor::toolchain::any ||
+ flag.toolchain == toolchain)
+ {
+ return c_option(toolchain, flag.opt, flag.arg);
+ }
+
+ return {};
+}
+
+std::vector<std::string> to_strings(ctor::toolchain toolchain,
+ const ctor::cxx_flag& flag)
+{
+ if(flag.toolchain == ctor::toolchain::any ||
+ flag.toolchain == toolchain)
+ {
+ return cxx_option(toolchain, flag.opt, flag.arg);
+ }
+
+ return {};
+}
+
+std::vector<std::string> to_strings(ctor::toolchain toolchain,
+ const ctor::ld_flag& flag)
+{
+ if(flag.toolchain == ctor::toolchain::any ||
+ flag.toolchain == toolchain)
+ {
+ return ld_option(toolchain, flag.opt, flag.arg);
+ }
+
+ return {};
+}
+
+std::vector<std::string> to_strings(ctor::toolchain toolchain,
+ const ctor::ar_flag& flag)
+{
+ if(flag.toolchain == ctor::toolchain::any ||
+ flag.toolchain == toolchain)
+ {
+ return ar_option(toolchain, flag.opt, flag.arg);
+ }
+
+ return {};
+}
+
+std::vector<std::string> to_strings(ctor::toolchain toolchain,
+ const ctor::asm_flag& flag)
+{
+ if(flag.toolchain == ctor::toolchain::any ||
+ flag.toolchain == toolchain)
+ {
+ return asm_option(toolchain, flag.opt, flag.arg);
+ }
+
+ return {};
+}
+
+namespace {
+ctor::toolchain guess_toolchain(const std::string& opt)
+{
+ if(opt.empty())
+ {
+ return ctor::toolchain::any;
+ }
+
+ if(opt[0] == '-')
+ {
+ return ctor::toolchain::gcc;
+ }
+
+ //if(opt[0] == '/')
+ //{
+ // return ctor::toolchain::msvc;
+ //}
+ return ctor::toolchain::any;
+}
+}
+
+template<>
+ctor::flag<ctor::c_opt>::flag(const char* str)
+{
+ *this = c_option(str, guess_toolchain(str));
+}
+
+template<>
+ctor::flag<ctor::cxx_opt>::flag(const char* str)
+{
+ *this = cxx_option(str, guess_toolchain(str));
+}
+
+template<>
+ctor::flag<ctor::ld_opt>::flag(const char* str)
+{
+ *this = ld_option(str, guess_toolchain(str));
+}
+
+template<>
+ctor::flag<ctor::ar_opt>::flag(const char* str)
+{
+ *this = ar_option(str, guess_toolchain(str));
+}
+
+template<>
+ctor::flag<ctor::asm_opt>::flag(const char* str)
+{
+ *this = asm_option(str, guess_toolchain(str));
+}
diff --git a/src/tools.h b/src/tools.h
new file mode 100644
index 0000000..b1285ec
--- /dev/null
+++ b/src/tools.h
@@ -0,0 +1,96 @@
+// -*- c++ -*-
+// Distributed under the BSD 2-Clause License.
+// See accompanying file LICENSE for details.
+#pragma once
+
+#include <vector>
+#include <string>
+#include <ostream>
+
+#include "ctor.h"
+
+
+std::ostream& operator<<(std::ostream& stream, const ctor::c_opt& opt);
+std::ostream& operator<<(std::ostream& stream, const ctor::cxx_opt& opt);
+std::ostream& operator<<(std::ostream& stream, const ctor::ld_opt& opt);
+std::ostream& operator<<(std::ostream& stream, const ctor::ar_opt& opt);
+std::ostream& operator<<(std::ostream& stream, const ctor::asm_opt& opt);
+
+
+//! Get tool-chain type from compiler path string
+ctor::toolchain getToolChain(const std::string& compiler);
+
+//! Get tool-chain type from output system (via configuration)
+ctor::toolchain getToolChain(ctor::output_system system);
+
+
+
+//! Get tool argument(s) for specific option type matching the supplied
+//! tool-chain
+std::vector<std::string> c_option(ctor::toolchain toolchain,
+ ctor::c_opt option,
+ const std::string& arg = {});
+
+//! Get tool argument(s) for specific option type matching the supplied
+//! tool-chain
+std::vector<std::string> cxx_option(ctor::toolchain toolchain,
+ ctor::cxx_opt option,
+ const std::string& arg = {});
+
+//! Get tool argument(s) for specific option type matching the supplied
+//! tool-chain
+std::vector<std::string> ld_option(ctor::toolchain toolchain,
+ ctor::ld_opt option,
+ const std::string& arg = {});
+
+//! Get tool argument(s) for specific option type matching the supplied
+//! tool-chain
+std::vector<std::string> ar_option(ctor::toolchain toolchain,
+ ctor::ar_opt option,
+ const std::string& arg = {});
+
+//! Get tool argument(s) for specific option type matching the supplied
+//! tool-chain
+std::vector<std::string> asm_option(ctor::toolchain toolchain,
+ ctor::asm_opt option,
+ const std::string& arg = {});
+
+
+
+//! Get ctor::c_opt enum value and argument from string,
+//! ie. { ctor::c_opt::inlude_path, "foo/bar" } from "-Ifoo/bar"
+//! Returns { ctor::c_opt::custom, flag } if unknown.
+ctor::c_flag c_option(const std::string& flag, ctor::toolchain toolchain);
+
+//! Get ctor::cxx_opt enum value and argument from string,
+//! ie. { ctor::cxx_opt::inlude_path, "foo/bar" } from "-Ifoo/bar"
+//! Returns { ctor::cxx_opt::custom, flag } if unknown.
+ctor::cxx_flag cxx_option(const std::string& flag, ctor::toolchain toolchain);
+
+//! Get ctor::ld_opt enum value and argument from string,
+//! ie. { ctor::ld_opt::inlude_path, "foo/bar" } from "-Ifoo/bar"
+//! Returns { ctor::ld_opt::custom, flag } if unknown.
+ctor::ld_flag ld_option(const std::string& flag, ctor::toolchain toolchain);
+
+//! Get ctor::ar_opt enum value and argument from string,
+//! ie. { ctor::ar_opt::inlude_path, "foo/bar" } from "-Ifoo/bar"
+//! Returns { ctor::ar_opt::custom, flag } if unknown.
+ctor::ar_flag ar_option(const std::string& flag, ctor::toolchain toolchain);
+
+//! Get ctor::asm_opt enum value and argument from string,
+//! ie. { ctor::asm_opt::inlude_path, "foo/bar" } from "-Ifoo/bar"
+//! Returns { ctor::asm_opt::custom, flag } if unknown.
+ctor::asm_flag asm_option(const std::string& flag, ctor::toolchain toolchain);
+
+
+
+std::vector<std::string> to_strings(ctor::toolchain toolchain,
+ const ctor::cxx_flag& flag);
+std::vector<std::string> to_strings(ctor::toolchain toolchain,
+ const ctor::c_flag& flag);
+std::vector<std::string> to_strings(ctor::toolchain toolchain,
+ const ctor::ld_flag& flag);
+std::vector<std::string> to_strings(ctor::toolchain toolchain,
+ const ctor::ar_flag& flag);
+std::vector<std::string> to_strings(ctor::toolchain toolchain,
+ const ctor::asm_flag& flag);
diff --git a/src/unittest.cc b/src/unittest.cc
index ade2d0a..237b2e3 100644
--- a/src/unittest.cc
+++ b/src/unittest.cc
@@ -6,29 +6,33 @@
#include <iostream>
#include "execute.h"
-#include "settings.h"
#include "task.h"
-int runUnitTests(std::list<std::shared_ptr<Task>>& tasks,
- const Settings& settings)
+int runUnitTests(std::set<std::shared_ptr<Task>>& tasks,
+ const ctor::settings& settings)
{
bool ok{true};
- std::cout << "Running unit-tests:\n";
+ std::cout << "Running unit-tests:" << std::endl;
// Run unit-tests
for(const auto& task : tasks)
{
- if(task->targetType() == TargetType::UnitTest)
+ if(task->targetType() == ctor::target_type::unit_test)
{
- std::cout << task->name() << ": ";
- auto ret = execute(task->target(), {}, false);
+ auto name = task->name();
+ if(name.empty())
+ {
+ name = task->target();
+ }
+ std::cout << name << ": " << std::flush;
+ auto ret = execute(task->targetFile(), {}, settings.verbose > 0);
ok &= ret == 0;
if(ret == 0)
{
- std::cout << "OK\n";
+ std::cout << " OK" << std::endl;
}
else
{
- std::cout << "FAILED\n";
+ std::cout << " FAILED" << std::endl;
}
}
}
diff --git a/src/unittest.h b/src/unittest.h
index 7eef0e2..2880319 100644
--- a/src/unittest.h
+++ b/src/unittest.h
@@ -3,11 +3,14 @@
// See accompanying file LICENSE for details.
#pragma once
-#include <list>
+#include <set>
#include <memory>
class Task;
-class Settings;
-int runUnitTests(std::list<std::shared_ptr<Task>>& tasks,
- const Settings& settings);
+namespace ctor {
+struct settings;
+} // namespace ctor::
+
+int runUnitTests(std::set<std::shared_ptr<Task>>& tasks,
+ const ctor::settings& settings);
diff --git a/src/util.cc b/src/util.cc
index 9bf83cc..ee56ede 100644
--- a/src/util.cc
+++ b/src/util.cc
@@ -80,12 +80,12 @@ std::vector<std::string> readDeps(const std::string& depFile)
return output;
}
-Language languageFromExtension(const std::filesystem::path& file)
+ctor::language languageFromExtension(const std::filesystem::path& file)
{
auto ext = file.extension().string();
if(ext == ".c")
{
- return Language::C;
+ return ctor::language::c;
}
if(ext == ".C" ||
@@ -96,17 +96,42 @@ Language languageFromExtension(const std::filesystem::path& file)
ext == ".cp" ||
ext == ".cxx")
{
- return Language::Cpp;
+ return ctor::language::cpp;
}
if(ext == ".s" ||
ext == ".S" ||
ext == ".asm")
{
- return Language::Asm;
+ return ctor::language::assembler;
}
std::cerr << "Could not deduce language from " << file.string() << "\n";
exit(1);
return {};
}
+
+namespace
+{
+bool isClean(char c)
+{
+ return c != '.' && c != '/';
+}
+}
+
+std::string cleanUp(const std::string& path)
+{
+ std::string cleaned;
+ for(const auto& c : path)
+ {
+ if(isClean(c))
+ {
+ cleaned += c;
+ }
+ else
+ {
+ cleaned += '_';
+ }
+ }
+ return cleaned;
+}
diff --git a/src/util.h b/src/util.h
index dc9cd41..c7318aa 100644
--- a/src/util.h
+++ b/src/util.h
@@ -3,11 +3,23 @@
// See accompanying file LICENSE for details.
#pragma once
-#include "libctor.h"
+#include "ctor.h"
#include <string>
#include <filesystem>
std::string readFile(const std::string& fileName);
std::vector<std::string> readDeps(const std::string& depFile);
-Language languageFromExtension(const std::filesystem::path& file);
+ctor::language languageFromExtension(const std::filesystem::path& file);
+std::string cleanUp(const std::string& path);
+
+template<typename T>
+void append(T& a, const T& b)
+{
+ a.insert(a.end(), b.begin(), b.end());
+}
+
+//using cxx_flags = std::vector<ctor::cxx_flag>;
+//using c_flags = std::vector<std::string>;
+//using ld_flags= std::vector<std::string>;
+//using asm_flags = std::vector<std::string>;
diff --git a/test/ctor.cc b/test/ctor.cc
index 6515c72..a2ad64d 100644
--- a/test/ctor.cc
+++ b/test/ctor.cc
@@ -1,16 +1,16 @@
// -*- c++ -*-
// Distributed under the BSD 2-Clause License.
// See accompanying file LICENSE for details.
-#include <libctor.h>
+#include <ctor.h>
namespace
{
-BuildConfigurations ctorTestConfigs()
+ctor::build_configurations ctorTestConfigs(const ctor::settings& settings)
{
return
{
{
- .type = TargetType::UnitTest,
+ .type = ctor::target_type::unit_test,
.target = "execute_test",
.sources = {
"execute_test.cc",
@@ -19,7 +19,7 @@ BuildConfigurations ctorTestConfigs()
},
.flags = {
.cxxflags = {
- "-std=c++20", "-O3", "-s", "-Wall", "-Werror",
+ "-std=c++20", "-O3", "-Wall", "-Werror",
"-I../src", "-Iuunit",
"-DOUTPUT=\"execute\"",
},
@@ -27,16 +27,16 @@ BuildConfigurations ctorTestConfigs()
},
},
{
- .type = TargetType::UnitTest,
+ .type = ctor::target_type::unit_test,
.target = "tasks_test",
.sources = {
"tasks_test.cc",
"testmain.cc",
},
- .depends = {"libctor.a"},
+ .depends = { "libctor_nomain.a" },
.flags = {
.cxxflags = {
- "-std=c++20", "-O3", "-s", "-Wall", "-Werror",
+ "-std=c++20", "-O3", "-Wall", "-Werror",
"-I../src", "-Iuunit",
"-DOUTPUT=\"tasks\"",
},
@@ -44,22 +44,66 @@ BuildConfigurations ctorTestConfigs()
},
},
{
- .type = TargetType::UnitTest,
+ .type = ctor::target_type::unit_test,
.target = "source_type_test",
.sources = {
"source_type_test.cc",
"testmain.cc",
},
- .depends = {"libctor.a"},
+ .depends = { "libctor_nomain.a" },
.flags = {
.cxxflags = {
- "-std=c++20", "-O3", "-s", "-Wall", "-Werror",
+ "-std=c++20", "-O3", "-Wall", "-Werror",
"-I../src", "-Iuunit",
"-DOUTPUT=\"source_type\"",
},
.ldflags = { "-pthread" },
},
},
+ {
+ .type = ctor::target_type::unit_test,
+ .target = "tools_test",
+ .sources = {
+ "tools_test.cc",
+ "testmain.cc",
+ "../src/tools.cc",
+ },
+ //.depends = { "libctor_nomain.a" },
+ .flags = {
+ .cxxflags = {
+ "-std=c++20", "-O3", "-Wall", "-Werror",
+ "-I../src", "-Iuunit",
+ "-DOUTPUT=\"tools\"",
+ },
+ },
+ },
+ {
+ .type = ctor::target_type::unit_test_library,
+ .target = "libctor_nomain.a",
+ .sources = {
+ "../src/build.cc",
+ "../src/configure.cc",
+ "../src/execute.cc",
+ "../src/rebuild.cc",
+ "../src/tasks.cc",
+ "../src/task.cc",
+ "../src/task_ar.cc",
+ "../src/task_cc.cc",
+ "../src/task_fn.cc",
+ "../src/task_ld.cc",
+ "../src/task_so.cc",
+ "../src/tools.cc",
+ "../src/util.cc",
+ "../src/externals_manual.cc",
+ },
+ .flags = {
+ .cxxflags = {
+ "-std=c++20", "-O3", "-Wall", "-Werror",
+ "-I../src",
+ },
+ .ldflags = { "-pthread" },
+ },
+ },
};
}
}
diff --git a/test/source_type_test.cc b/test/source_type_test.cc
index 47d820d..288f1e5 100644
--- a/test/source_type_test.cc
+++ b/test/source_type_test.cc
@@ -1,38 +1,40 @@
-#include <uunit.h>
-
-#include <libctor.h>
+#include <ctor.h>
#include <task_cc.h>
-#include <settings.h>
-std::ostream& operator<<(std::ostream& stream, const Language& lang)
+std::ostream& operator<<(std::ostream& stream, const ctor::language& lang);
+
+#include <uunit.h>
+
+std::ostream& operator<<(std::ostream& stream, const ctor::language& lang)
{
switch(lang)
{
- case Language::Auto:
- stream << "Language::Auto";
+ case ctor::language::automatic:
+ stream << "ctor::language::automatic";
break;
- case Language::C:
- stream << "Language::C";
+ case ctor::language::c:
+ stream << "ctor::language::c";
break;
- case Language::Cpp:
- stream << "Language::Cpp";
+ case ctor::language::cpp:
+ stream << "ctor::language::cpp";
break;
- case Language::Asm:
- stream << "Language::Asm";
+ case ctor::language::assembler:
+ stream << "ctor::language::assembler";
break;
}
return stream;
}
+
class TestableTaskCC
: public TaskCC
{
public:
- TestableTaskCC(const Source& source)
+ TestableTaskCC(const ctor::source& source)
: TaskCC({}, {}, "build", source)
{}
- Language language() const
+ ctor::language language() const
{
return source_language;
}
@@ -51,22 +53,22 @@ public:
{
{ // c++
TestableTaskCC task("hello.cc");
- uASSERT_EQUAL(Language::Cpp, task.language());
+ uASSERT_EQUAL(ctor::language::cpp, task.language());
}
{ // c
TestableTaskCC task("hello.c");
- uASSERT_EQUAL(Language::C, task.language());
+ uASSERT_EQUAL(ctor::language::c, task.language());
}
{ // asm
TestableTaskCC task("hello.s");
- uASSERT_EQUAL(Language::Asm, task.language());
+ uASSERT_EQUAL(ctor::language::assembler, task.language());
}
{ // custom/explicit language
- TestableTaskCC task( {"hello.foo", Language::Asm} );
- uASSERT_EQUAL(Language::Asm, task.language());
+ TestableTaskCC task( {"hello.foo", ctor::language::assembler} );
+ uASSERT_EQUAL(ctor::language::assembler, task.language());
}
// Note: Failure state will result in exit(1) so cannot be tested
diff --git a/test/suite/ctor_files/ctor.cc.bar b/test/suite/ctor_files/ctor.cc.bar
index 92456cb..218f9cc 100644
--- a/test/suite/ctor_files/ctor.cc.bar
+++ b/test/suite/ctor_files/ctor.cc.bar
@@ -1,12 +1,12 @@
// -*- c++ -*-
// Distributed under the BSD 2-Clause License.
// See accompanying file LICENSE for details.
-#include <libctor.h>
+#include <ctor.h>
//#include "config.h"
namespace
{
-BuildConfigurations ctorConfigs()
+ctor::build_configurations ctorConfigs(const ctor::settings& settings)
{
return
{
@@ -30,17 +30,19 @@ BuildConfigurations ctorConfigs()
};
}
-ExternalConfigurations ctorExtConfigs()
+ctor::external_configurations ctorExtConfigs(const ctor::settings& settings)
{
return
{
{
.name = "bar",
- .flags = {
- .cxxflags = { "-D_A_", "-DBAR"},
- .cflags = { "-D_B_" },
- .ldflags = { "-D_C_" },
- .asmflags = { "-D_D_" },
+ .external = ctor::external_manual{
+ .flags = {
+ .cflags = { "-D_B_" },
+ .cxxflags = { "-D_A_", "-DBAR"},
+ .ldflags = { "-D_C_" },
+ .asmflags = { "-D_D_" },
+ },
},
// Creates --with-foo-prefix arg to configure which will be used for
// -L and -I flags.
diff --git a/test/suite/ctor_files/ctor.cc.base b/test/suite/ctor_files/ctor.cc.base
index 6c60513..eab39c4 100644
--- a/test/suite/ctor_files/ctor.cc.base
+++ b/test/suite/ctor_files/ctor.cc.base
@@ -1,12 +1,12 @@
// -*- c++ -*-
// Distributed under the BSD 2-Clause License.
// See accompanying file LICENSE for details.
-#include <libctor.h>
+#include <ctor.h>
//#include "config.h"
namespace
{
-BuildConfigurations ctorConfigs()
+ctor::build_configurations ctorConfigs(const ctor::settings& settings)
{
return
{
@@ -30,17 +30,20 @@ BuildConfigurations ctorConfigs()
};
}
-ExternalConfigurations ctorExtConfigs()
+ctor::external_configurations ctorExtConfigs(const ctor::settings& settings)
{
return
{
{
.name = "bar",
- .flags = {
- .cxxflags = { "-D_A_", "-DFOO"},
- .cflags = { "-D_B_" },
- .ldflags = { "-D_C_" },
- .asmflags = { "-D_D_" },
+ .external = ctor::external_manual
+ {
+ .flags = {
+ .cflags = { "-D_B_" },
+ .cxxflags = { "-D_A_", "-DFOO"},
+ .ldflags = { "-D_C_" },
+ .asmflags = { "-D_D_" },
+ },
},
// Creates --with-foo-prefix arg to configure which will be used for
// -L and -I flags.
diff --git a/test/suite/ctor_files/ctor.cc.multi b/test/suite/ctor_files/ctor.cc.multi
index 9db2517..2b88afe 100644
--- a/test/suite/ctor_files/ctor.cc.multi
+++ b/test/suite/ctor_files/ctor.cc.multi
@@ -1,14 +1,14 @@
// -*- c++ -*-
// Distributed under the BSD 2-Clause License.
// See accompanying file LICENSE for details.
-#include <libctor.h>
+#include <ctor.h>
//#include "config.h"
#include "foobar.h"
namespace
{
-BuildConfigurations ctorConfigs()
+ctor::build_configurations ctorConfigs(const ctor::settings& settings)
{
return
{
@@ -32,17 +32,19 @@ BuildConfigurations ctorConfigs()
};
}
-ExternalConfigurations ctorExtConfigs()
+ctor::external_configurations ctorExtConfigs(const ctor::settings& settings)
{
return
{
{
.name = "bar",
- .flags = {
- .cxxflags = { "-D_A_", "-DFOO"},
- .cflags = { "-D_B_" },
- .ldflags = { "-D_C_" },
- .asmflags = { "-D_D_" },
+ .external = ctor::external_manual{
+ .flags = {
+ .cflags = { "-D_B_" },
+ .cxxflags = { "-D_A_", "-DFOO"},
+ .ldflags = { "-D_C_" },
+ .asmflags = { "-D_D_" },
+ },
},
// Creates --with-foo-prefix arg to configure which will be used for
// -L and -I flags.
diff --git a/test/suite/test.sh b/test/suite/test.sh
index c980154..c112351 100755
--- a/test/suite/test.sh
+++ b/test/suite/test.sh
@@ -1,4 +1,9 @@
#!/bin/bash
+: ${CXX:=g++}
+: ${CTORDIR:=../../build}
+: ${BUILDDIR:=build}
+
+CXX=$(which $CXX)
function fail
{
@@ -13,21 +18,22 @@ function ctor
}
# Wipe the board
-rm -Rf build
+rm -Rf ${BUILDDIR}
rm -f configuration.cc
rm -f ctor
+echo "** ctor_files/ctor.cc.base"
cp ctor_files/ctor.cc.base ctor.cc
# Compile bootstrap binary
-g++ -pthread -std=c++20 -L../../build -lctor -I../../src ctor.cc -o ctor || fail ${LINENO}
+$CXX -pthread -std=c++20 -L${CTORDIR} -lctor -I../../src ctor.cc -o ctor || fail ${LINENO}
# No build files should have been created yet
-[ -d build ] && fail ${LINENO}
+[ -d ${BUILDDIR} ] && fail ${LINENO}
# capture md5 sum of ctor binary before configure is called
MD5=`md5sum ctor`
-ctor configure --ctor-includedir ../../src --ctor-libdir ../../build
+ctor configure --ctor-includedir ../../src --ctor-libdir=${CTORDIR} --build-dir=${BUILDDIR}
# ctor should be rebuilt at this point, so md5 sum should have changed
(echo $MD5 | md5sum --status -c) && fail ${LINENO}
@@ -36,7 +42,7 @@ ctor configure --ctor-includedir ../../src --ctor-libdir ../../build
[ ! -f configuration.cc ] && fail ${LINENO}
# Shouldn't compile anything yet - only configure
-[ -f build/hello-hello_cc.o ] && fail ${LINENO}
+[ -f ${BUILDDIR}/hello-hello_cc.o ] && fail ${LINENO}
MD5=`md5sum ctor`
@@ -44,12 +50,12 @@ MD5=`md5sum ctor`
ctor -v
# Compiled object should now exist
-[ ! -f build/hello-hello_cc.o ] && fail ${LINENO}
+[ ! -f ${BUILDDIR}/hello-hello_cc.o ] && fail ${LINENO}
# ctor should not have been rebuilt, so md5 sum should be the same
(echo $MD5 | md5sum --status -c) || fail ${LINENO}
-MOD1=`stat -c %Y build/hello-hello_cc.o`
+MOD1=`stat -c %Y ${BUILDDIR}/hello-hello_cc.o`
touch hello.cc
sleep 1.1
@@ -57,10 +63,11 @@ sleep 1.1
ctor -v
# Object file should have been recompiled
-MOD2=`stat -c %Y build/hello-hello_cc.o`
+MOD2=`stat -c %Y ${BUILDDIR}/hello-hello_cc.o`
[[ $MOD1 == $MOD2 ]] && fail ${LINENO}
# Replacve -DFOO with -DBAR in foo external.cxxflags
+echo "** ctor_files/ctor.cc.bar"
cp ctor_files/ctor.cc.bar ctor.cc
MD5C=`md5sum configuration.cc`
@@ -71,22 +78,23 @@ sleep 1.1
# Run normally to reconfigure, rebuild ctor and rebuild hello.cc
ctor -v
-MOD2=`stat -c %Y build/hello-hello_cc.o`
+MOD2=`stat -c %Y ${BUILDDIR}/hello-hello_cc.o`
[[ $MOD1 == $MOD2 ]] && fail ${LINENO}
(echo $MD5C | md5sum --status -c) && fail ${LINENO}
(echo $MD5 | md5sum --status -c) && fail ${LINENO}
+echo "** ctor_files/ctor.cc.multi"
cp ctor_files/ctor.cc.multi ctor.cc
MD5C=`md5sum configuration.cc`
MD5=`md5sum ctor`
-MOD1=`stat -c %Y build/hello-hello_cc.o`
+MOD1=`stat -c %Y ${BUILDDIR}/hello-hello_cc.o`
sleep 1.1
# Run normally to reconfigure, rebuild ctor and rebuild hello.cc
ctor -v
-MOD2=`stat -c %Y build/hello-hello_cc.o`
+MOD2=`stat -c %Y ${BUILDDIR}/hello-hello_cc.o`
[[ $MOD1 == $MOD2 ]] && fail ${LINENO}
(echo $MD5C | md5sum --status -c) && fail ${LINENO}
(echo $MD5 | md5sum --status -c) && fail ${LINENO}
@@ -102,3 +110,5 @@ ctor -v
MOD2=`stat -c %Y ctor`
[[ $MOD1 == $MOD2 ]] && fail ${LINENO}
+
+exit 0
diff --git a/test/tasks_test.cc b/test/tasks_test.cc
index 8a15fcd..5f1db26 100644
--- a/test/tasks_test.cc
+++ b/test/tasks_test.cc
@@ -1,12 +1,11 @@
#include <uunit.h>
-#include <libctor.h>
+#include <ctor.h>
#include <tasks.h>
-#include <settings.h>
namespace
{
-BuildConfigurations ctorTestConfigs1()
+ctor::build_configurations ctorTestConfigs1(const ctor::settings&)
{
return
{
@@ -20,7 +19,7 @@ BuildConfigurations ctorTestConfigs1()
};
}
-BuildConfigurations ctorTestConfigs2()
+ctor::build_configurations ctorTestConfigs2(const ctor::settings&)
{
return
{
@@ -37,6 +36,19 @@ BuildConfigurations ctorTestConfigs2()
REG(ctorTestConfigs1);
REG(ctorTestConfigs2);
+std::size_t count(const std::set<std::shared_ptr<Task>>& tasks,
+ const std::string& name)
+{
+ auto cnt{0u};
+ for(const auto& task : tasks)
+ {
+ if(task->target() == name)
+ {
+ cnt++;
+ }
+ }
+ return cnt;
+}
class TestTask
: public Task
@@ -44,7 +56,7 @@ class TestTask
public:
TestTask(const std::string& name, bool dirty,
const std::vector<std::string>& deps = {})
- : Task({})
+ : Task({}, {}, {})
, task_name(name)
, task_dirty(dirty)
, task_deps(deps)
@@ -55,6 +67,7 @@ public:
int clean() override { return 0; }
std::vector<std::string> depends() const override { return task_deps; }
std::string target() const override { return task_name; }
+ std::filesystem::path targetFile() const override { return {}; }
bool derived() const override { return false; }
bool dirtyInner() override { return task_dirty; }
@@ -78,7 +91,7 @@ public:
void getTargets_test()
{
using namespace std::string_literals;
- Settings settings{};
+ ctor::settings settings{};
const auto& targets = getTargets(settings);
uASSERT_EQUAL(4u, targets.size());
@@ -96,34 +109,26 @@ public:
void getTasks_test()
{
using namespace std::string_literals;
- Settings settings{ .builddir = "foo" };
+ ctor::settings settings{ .builddir = "foo" };
{
auto tasks = getTasks(settings);
uASSERT_EQUAL(6u, tasks.size());
- auto task = tasks.begin();
- uASSERT_EQUAL("foo/test/target1-foo_cc.o"s, (*task)->target());
- task++;
- uASSERT_EQUAL("foo/test/target1-bar_c.o"s, (*task)->target());
- task++;
- uASSERT_EQUAL("foo/test/target1"s, (*task)->target());
- task++;
- uASSERT_EQUAL("foo/test/target2"s, (*task)->target());
- task++;
- uASSERT_EQUAL("foo/test/target3"s, (*task)->target());
- task++;
- uASSERT_EQUAL("foo/test/target4"s, (*task)->target());
+ // Note: count() is used here because the order of
+ // std::set<std::shared_ptr<T>> is not deterministic.
+ uASSERT_EQUAL(1u, count(tasks, "target1"s));
+ uASSERT_EQUAL(1u, count(tasks, "target2"s));
+ uASSERT_EQUAL(1u, count(tasks, "target3"s));
+ uASSERT_EQUAL(1u, count(tasks, "target4"s));
+ uASSERT_EQUAL(1u, count(tasks, "test/target1-foo_cc.o"s));
+ uASSERT_EQUAL(1u, count(tasks, "test/target1-bar_c.o"s));
}
{
auto tasks = getTasks(settings, {"target1", "target3"});
uASSERT_EQUAL(4u, tasks.size());
- auto task = tasks.begin();
- uASSERT_EQUAL("foo/test/target1-foo_cc.o"s, (*task)->target());
- task++;
- uASSERT_EQUAL("foo/test/target1-bar_c.o"s, (*task)->target());
- task++;
- uASSERT_EQUAL("foo/test/target1"s, (*task)->target());
- task++;
- uASSERT_EQUAL("foo/test/target3"s, (*task)->target());
+ uASSERT_EQUAL(1u, count(tasks, "target1"s));
+ uASSERT_EQUAL(1u, count(tasks, "target3"s));
+ uASSERT_EQUAL(1u, count(tasks, "test/target1-foo_cc.o"s));
+ uASSERT_EQUAL(1u, count(tasks, "test/target1-bar_c.o"s));
}
{
auto tasks = getTasks(settings, {"no-such-target"});
@@ -134,11 +139,11 @@ public:
void getNextTask_test()
{
using namespace std::string_literals;
- Settings settings{};
+ ctor::settings settings{};
{ // Zero (Empty)
- std::list<std::shared_ptr<Task>> allTasks;
- std::list<std::shared_ptr<Task>> dirtyTasks;
+ std::set<std::shared_ptr<Task>> allTasks;
+ std::set<std::shared_ptr<Task>> dirtyTasks;
for(auto& task : dirtyTasks)
{
@@ -151,10 +156,10 @@ public:
{ // Zero (One task, no dirty)
auto task1 = std::make_shared<TestTask>("task1", false);
- std::list<std::shared_ptr<Task>> allTasks;
- allTasks.push_back(task1);
+ std::set<std::shared_ptr<Task>> allTasks;
+ allTasks.insert(task1);
- std::list<std::shared_ptr<Task>> dirtyTasks;
+ std::set<std::shared_ptr<Task>> dirtyTasks;
for(auto& task : dirtyTasks)
{
@@ -167,11 +172,11 @@ public:
{ // One (One task, one dirty)
auto task1 = std::make_shared<TestTask>("task1", true);
- std::list<std::shared_ptr<Task>> allTasks;
- allTasks.push_back(task1);
+ std::set<std::shared_ptr<Task>> allTasks;
+ allTasks.insert(task1);
- std::list<std::shared_ptr<Task>> dirtyTasks;
- dirtyTasks.push_back(task1);
+ std::set<std::shared_ptr<Task>> dirtyTasks;
+ dirtyTasks.insert(task1);
for(auto& task : dirtyTasks)
{
@@ -186,12 +191,12 @@ public:
auto task1 = std::make_shared<TestTask>("task1", false);
auto task2 = std::make_shared<TestTask>("task2", true);
- std::list<std::shared_ptr<Task>> allTasks;
- allTasks.push_back(task1);
- allTasks.push_back(task2);
+ std::set<std::shared_ptr<Task>> allTasks;
+ allTasks.insert(task1);
+ allTasks.insert(task2);
- std::list<std::shared_ptr<Task>> dirtyTasks;
- dirtyTasks.push_back(task2);
+ std::set<std::shared_ptr<Task>> dirtyTasks;
+ dirtyTasks.insert(task2);
for(auto& task : dirtyTasks)
{
@@ -208,12 +213,12 @@ public:
std::vector<std::string> deps = {"task1"};
auto task2 = std::make_shared<TestTask>("task2", true, deps);
- std::list<std::shared_ptr<Task>> allTasks;
- allTasks.push_back(task1);
- allTasks.push_back(task2);
+ std::set<std::shared_ptr<Task>> allTasks;
+ allTasks.insert(task1);
+ allTasks.insert(task2);
- std::list<std::shared_ptr<Task>> dirtyTasks;
- dirtyTasks.push_back(task2);
+ std::set<std::shared_ptr<Task>> dirtyTasks;
+ dirtyTasks.insert(task2);
for(auto& task : dirtyTasks)
{
@@ -230,13 +235,13 @@ public:
std::vector<std::string> deps = {"task1"};
auto task2 = std::make_shared<TestTask>("task2", true, deps);
- std::list<std::shared_ptr<Task>> allTasks;
- allTasks.push_back(task2);
- allTasks.push_back(task1);
+ std::set<std::shared_ptr<Task>> allTasks;
+ allTasks.insert(task2);
+ allTasks.insert(task1);
- std::list<std::shared_ptr<Task>> dirtyTasks;
- dirtyTasks.push_back(task2);
- dirtyTasks.push_back(task1);
+ std::set<std::shared_ptr<Task>> dirtyTasks;
+ dirtyTasks.insert(task2);
+ dirtyTasks.insert(task1);
for(auto& task : dirtyTasks)
{
diff --git a/test/tools_test.cc b/test/tools_test.cc
new file mode 100644
index 0000000..7127b8d
--- /dev/null
+++ b/test/tools_test.cc
@@ -0,0 +1,930 @@
+#include <vector>
+#include <string>
+#include <ostream>
+#include <initializer_list>
+#include <cassert>
+
+#include <tools.h>
+
+std::ostream& operator<<(std::ostream& stream, const ctor::toolchain& toolchain)
+{
+ switch(toolchain)
+ {
+ case ctor::toolchain::none:
+ stream << "ctor::toolchain::none";
+ break;
+ case ctor::toolchain::any:
+ stream << "ctor::toolchain::any";
+ break;
+ case ctor::toolchain::gcc:
+ stream << "ctor::toolchain::gcc";
+ break;
+ case ctor::toolchain::clang:
+ stream << "ctor::toolchain::clang";
+ break;
+ }
+ return stream;
+}
+
+std::ostream& operator<<(std::ostream& stream, const std::vector<std::string>& vs)
+{
+ bool first{true};
+ stream << "{ ";
+ for(const auto& v : vs)
+ {
+ if(!first)
+ {
+ stream << ", ";
+ }
+ stream << "'" << v << "'";
+ first = false;
+ }
+ stream << " }";
+
+ return stream;
+}
+
+std::ostream& operator<<(std::ostream& stream, const ctor::c_flag& flag)
+{
+ stream << "{" << flag.opt << ", \"" << flag.arg << "\", " << flag.toolchain << "}";
+ return stream;
+}
+
+std::ostream& operator<<(std::ostream& stream, const ctor::cxx_flag& flag)
+{
+ stream << "{" << flag.opt << ", \"" << flag.arg << "\", " << flag.toolchain << "}";
+ return stream;
+}
+
+std::ostream& operator<<(std::ostream& stream, const ctor::ld_flag& flag)
+{
+ stream << "{" << flag.opt << ", \"" << flag.arg << "\", " << flag.toolchain << "}";
+ return stream;
+}
+
+std::ostream& operator<<(std::ostream& stream, const ctor::ar_flag& flag)
+{
+ stream << "{" << flag.opt << ", \"" << flag.arg << "\", " << flag.toolchain << "}";
+ return stream;
+}
+
+std::ostream& operator<<(std::ostream& stream, const ctor::asm_flag& flag)
+{
+ stream << "{" << flag.opt << ", \"" << flag.arg << "\", " << flag.toolchain << "}";
+ return stream;
+}
+
+bool operator!=(const ctor::c_flag& a, const ctor::c_flag& b)
+{
+ return
+ a.opt != b.opt ||
+ a.arg != b.arg ||
+ a.toolchain != b.toolchain;
+}
+
+bool operator!=(const ctor::cxx_flag& a, const ctor::cxx_flag& b)
+{
+ return
+ a.opt != b.opt ||
+ a.arg != b.arg ||
+ a.toolchain != b.toolchain;
+}
+bool operator!=(const ctor::ld_flag& a, const ctor::ld_flag& b)
+{
+ return
+ a.opt != b.opt ||
+ a.arg != b.arg ||
+ a.toolchain != b.toolchain;
+}
+
+bool operator!=(const ctor::ar_flag& a, const ctor::ar_flag& b)
+{
+ return
+ a.opt != b.opt ||
+ a.arg != b.arg ||
+ a.toolchain != b.toolchain;
+}
+bool operator!=(const ctor::asm_flag& a, const ctor::asm_flag& b)
+{
+ return
+ a.opt != b.opt ||
+ a.arg != b.arg ||
+ a.toolchain != b.toolchain;
+}
+
+#include <uunit.h>
+
+namespace {
+std::string conf_host_cxx{};
+std::string conf_build_cxx{};
+}
+
+const ctor::configuration& ctor::get_configuration()
+{
+ static ctor::configuration cfg;
+ return cfg;
+}
+
+const std::string& ctor::configuration::get(const std::string& key, const std::string& defval) const
+{
+ if(key == ctor::cfg::host_cxx)
+ {
+ return conf_host_cxx;
+ }
+
+ if(key == ctor::cfg::build_cxx)
+ {
+ return conf_build_cxx;
+ }
+
+ assert(false); // bad key
+
+ static std::string res{};
+ return res;
+}
+
+class ToolsTest
+ : public uUnit
+{
+public:
+ ToolsTest()
+ {
+ uTEST(ToolsTest::getToolChain_test);
+
+ uTEST(ToolsTest::getOption_toolchain_c_test);
+ uTEST(ToolsTest::getOption_toolchain_cxx_test);
+ uTEST(ToolsTest::getOption_toolchain_ld_test);
+ uTEST(ToolsTest::getOption_toolchain_ar_test);
+ uTEST(ToolsTest::getOption_toolchain_asm_test);
+
+ uTEST(ToolsTest::getOption_str_c_test);
+ uTEST(ToolsTest::getOption_str_cxx_test);
+ uTEST(ToolsTest::getOption_str_ld_test);
+ uTEST(ToolsTest::getOption_str_ar_test);
+ uTEST(ToolsTest::getOption_str_asm_test);
+
+ uTEST(ToolsTest::to_strings_c_test);
+ uTEST(ToolsTest::to_strings_cxx_test);
+ uTEST(ToolsTest::to_strings_ld_test);
+ uTEST(ToolsTest::to_strings_ar_test);
+ uTEST(ToolsTest::to_strings_asm_test);
+ }
+
+ void getToolChain_test()
+ {
+ uASSERT_EQUAL(ctor::toolchain::gcc, getToolChain("/usr/bin/g++"));
+ uASSERT_EQUAL(ctor::toolchain::gcc, getToolChain("/usr/bin/g++-10"));
+ uASSERT_EQUAL(ctor::toolchain::gcc, getToolChain("/usr/bin/x86_64-pc-linux-gnu-g++-9.3.0"));
+ uASSERT_EQUAL(ctor::toolchain::clang, getToolChain("/usr/bin/clang++"));
+ uASSERT_EQUAL(ctor::toolchain::clang, getToolChain("/usr/bin/clang++-16"));
+ uASSERT_EQUAL(ctor::toolchain::clang, getToolChain("/usr/lib/llvm/16/bin/i686-pc-linux-gnu-clang++-16"));
+ }
+
+
+ void getOption_toolchain_c_test()
+ {
+ std::vector<std::string> exp;
+ std::vector<std::string> act;
+
+ //
+ // gcc
+ //
+ exp = { "-o", "foo" };
+ act = c_option(ctor::toolchain::gcc, ctor::c_opt::output, "foo");
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "-g" };
+ act = c_option(ctor::toolchain::gcc, ctor::c_opt::debug);
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "-Wall" };
+ act = c_option(ctor::toolchain::gcc, ctor::c_opt::warn_all);
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "-Werror" };
+ act = c_option(ctor::toolchain::gcc, ctor::c_opt::warnings_as_errors);
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "-MMD" };
+ act = c_option(ctor::toolchain::gcc, ctor::c_opt::generate_dep_tree);
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "-c" };
+ act = c_option(ctor::toolchain::gcc, ctor::c_opt::no_link);
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "-Ifoo" };
+ act = c_option(ctor::toolchain::gcc, ctor::c_opt::include_path, "foo");
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "-std=foo" };
+ act = c_option(ctor::toolchain::gcc, ctor::c_opt::c_std, "foo");
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "-Ofoo" };
+ act = c_option(ctor::toolchain::gcc, ctor::c_opt::optimization, "foo");
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "-fPIC" };
+ act = c_option(ctor::toolchain::gcc, ctor::c_opt::position_independent_code);
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "-fPIE" };
+ act = c_option(ctor::toolchain::gcc, ctor::c_opt::position_independent_executable);
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "-foo" };
+ act = c_option(ctor::toolchain::gcc, ctor::c_opt::custom, "-foo");
+ uASSERT_EQUAL(exp, act);
+
+ //
+ // clang
+ //
+ exp = { "-o", "foo" };
+ act = c_option(ctor::toolchain::clang, ctor::c_opt::output, "foo");
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "-g" };
+ act = c_option(ctor::toolchain::clang, ctor::c_opt::debug);
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "-Wall" };
+ act = c_option(ctor::toolchain::clang, ctor::c_opt::warn_all);
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "-Werror" };
+ act = c_option(ctor::toolchain::clang, ctor::c_opt::warnings_as_errors);
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "-MMD" };
+ act = c_option(ctor::toolchain::clang, ctor::c_opt::generate_dep_tree);
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "-c" };
+ act = c_option(ctor::toolchain::clang, ctor::c_opt::no_link);
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "-Ifoo" };
+ act = c_option(ctor::toolchain::clang, ctor::c_opt::include_path, "foo");
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "-std=foo" };
+ act = c_option(ctor::toolchain::clang, ctor::c_opt::c_std, "foo");
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "-Ofoo" };
+ act = c_option(ctor::toolchain::clang, ctor::c_opt::optimization, "foo");
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "-fPIC" };
+ act = c_option(ctor::toolchain::clang, ctor::c_opt::position_independent_code);
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "-fPIE" };
+ act = c_option(ctor::toolchain::clang, ctor::c_opt::position_independent_executable);
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "-foo" };
+ act = c_option(ctor::toolchain::clang, ctor::c_opt::custom, "-foo");
+ uASSERT_EQUAL(exp, act);
+
+ //
+ // any
+ //
+ exp = { "{ctor::c_opt::output, \"foo\"}" };
+ act = c_option(ctor::toolchain::any, ctor::c_opt::output, "foo");
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "{ctor::c_opt::debug}" };
+ act = c_option(ctor::toolchain::any, ctor::c_opt::debug);
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "{ctor::c_opt::warn_all}" };
+ act = c_option(ctor::toolchain::any, ctor::c_opt::warn_all);
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "{ctor::c_opt::warnings_as_errors}" };
+ act = c_option(ctor::toolchain::any, ctor::c_opt::warnings_as_errors);
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "{ctor::c_opt::generate_dep_tree}" };
+ act = c_option(ctor::toolchain::any, ctor::c_opt::generate_dep_tree);
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "{ctor::c_opt::no_link}" };
+ act = c_option(ctor::toolchain::any, ctor::c_opt::no_link);
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "{ctor::c_opt::include_path, \"foo\"}" };
+ act = c_option(ctor::toolchain::any, ctor::c_opt::include_path, "foo");
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "{ctor::c_opt::c_std, \"foo\"}" };
+ act = c_option(ctor::toolchain::any, ctor::c_opt::c_std, "foo");
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "{ctor::c_opt::optimization, \"foo\"}" };
+ act = c_option(ctor::toolchain::any, ctor::c_opt::optimization, "foo");
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "{ctor::c_opt::position_independent_code}" };
+ act = c_option(ctor::toolchain::any, ctor::c_opt::position_independent_code);
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "{ctor::c_opt::position_independent_executable}" };
+ act = c_option(ctor::toolchain::any, ctor::c_opt::position_independent_executable);
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "{ctor::c_opt::custom, \"-foo\"}" };
+ act = c_option(ctor::toolchain::any, ctor::c_opt::custom, "-foo");
+ uASSERT_EQUAL(exp, act);
+ }
+
+ void getOption_toolchain_cxx_test()
+ {
+ std::vector<std::string> exp;
+ std::vector<std::string> act;
+
+ //
+ // gcc
+ //
+ exp = { "-o", "foo" };
+ act = cxx_option(ctor::toolchain::gcc, ctor::cxx_opt::output, "foo");
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "-g" };
+ act = cxx_option(ctor::toolchain::gcc, ctor::cxx_opt::debug);
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "-Wall" };
+ act = cxx_option(ctor::toolchain::gcc, ctor::cxx_opt::warn_all);
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "-Werror" };
+ act = cxx_option(ctor::toolchain::gcc, ctor::cxx_opt::warnings_as_errors);
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "-MMD" };
+ act = cxx_option(ctor::toolchain::gcc, ctor::cxx_opt::generate_dep_tree);
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "-c" };
+ act = cxx_option(ctor::toolchain::gcc, ctor::cxx_opt::no_link);
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "-Ifoo" };
+ act = cxx_option(ctor::toolchain::gcc, ctor::cxx_opt::include_path, "foo");
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "-std=foo" };
+ act = cxx_option(ctor::toolchain::gcc, ctor::cxx_opt::cpp_std, "foo");
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "-Ofoo" };
+ act = cxx_option(ctor::toolchain::gcc, ctor::cxx_opt::optimization, "foo");
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "-fPIC" };
+ act = cxx_option(ctor::toolchain::gcc, ctor::cxx_opt::position_independent_code);
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "-fPIE" };
+ act = cxx_option(ctor::toolchain::gcc, ctor::cxx_opt::position_independent_executable);
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "-foo" };
+ act = cxx_option(ctor::toolchain::gcc, ctor::cxx_opt::custom, "-foo");
+ uASSERT_EQUAL(exp, act);
+
+ //
+ // clang
+ //
+ exp = { "-o", "foo" };
+ act = cxx_option(ctor::toolchain::clang, ctor::cxx_opt::output, "foo");
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "-g" };
+ act = cxx_option(ctor::toolchain::clang, ctor::cxx_opt::debug);
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "-Wall" };
+ act = cxx_option(ctor::toolchain::clang, ctor::cxx_opt::warn_all);
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "-Werror" };
+ act = cxx_option(ctor::toolchain::clang, ctor::cxx_opt::warnings_as_errors);
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "-MMD" };
+ act = cxx_option(ctor::toolchain::clang, ctor::cxx_opt::generate_dep_tree);
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "-c" };
+ act = cxx_option(ctor::toolchain::clang, ctor::cxx_opt::no_link);
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "-Ifoo" };
+ act = cxx_option(ctor::toolchain::clang, ctor::cxx_opt::include_path, "foo");
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "-std=foo" };
+ act = cxx_option(ctor::toolchain::clang, ctor::cxx_opt::cpp_std, "foo");
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "-Ofoo" };
+ act = cxx_option(ctor::toolchain::clang, ctor::cxx_opt::optimization, "foo");
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "-fPIC" };
+ act = cxx_option(ctor::toolchain::clang, ctor::cxx_opt::position_independent_code);
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "-fPIE" };
+ act = cxx_option(ctor::toolchain::clang, ctor::cxx_opt::position_independent_executable);
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "-foo" };
+ act = cxx_option(ctor::toolchain::clang, ctor::cxx_opt::custom, "-foo");
+ uASSERT_EQUAL(exp, act);
+
+ //
+ // any
+ //
+ exp = { "{ctor::cxx_opt::output, \"foo\"}" };
+ act = cxx_option(ctor::toolchain::any, ctor::cxx_opt::output, "foo");
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "{ctor::cxx_opt::debug}" };
+ act = cxx_option(ctor::toolchain::any, ctor::cxx_opt::debug);
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "{ctor::cxx_opt::warn_all}" };
+ act = cxx_option(ctor::toolchain::any, ctor::cxx_opt::warn_all);
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "{ctor::cxx_opt::warnings_as_errors}" };
+ act = cxx_option(ctor::toolchain::any, ctor::cxx_opt::warnings_as_errors);
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "{ctor::cxx_opt::generate_dep_tree}" };
+ act = cxx_option(ctor::toolchain::any, ctor::cxx_opt::generate_dep_tree);
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "{ctor::cxx_opt::no_link}" };
+ act = cxx_option(ctor::toolchain::any, ctor::cxx_opt::no_link);
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "{ctor::cxx_opt::include_path, \"foo\"}" };
+ act = cxx_option(ctor::toolchain::any, ctor::cxx_opt::include_path, "foo");
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "{ctor::cxx_opt::cpp_std, \"foo\"}" };
+ act = cxx_option(ctor::toolchain::any, ctor::cxx_opt::cpp_std, "foo");
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "{ctor::cxx_opt::optimization, \"foo\"}" };
+ act = cxx_option(ctor::toolchain::any, ctor::cxx_opt::optimization, "foo");
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "{ctor::cxx_opt::position_independent_code}" };
+ act = cxx_option(ctor::toolchain::any, ctor::cxx_opt::position_independent_code);
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "{ctor::cxx_opt::position_independent_executable}" };
+ act = cxx_option(ctor::toolchain::any, ctor::cxx_opt::position_independent_executable);
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "{ctor::cxx_opt::custom, \"-foo\"}" };
+ act = cxx_option(ctor::toolchain::any, ctor::cxx_opt::custom, "-foo");
+ uASSERT_EQUAL(exp, act);
+ }
+
+ void getOption_toolchain_ld_test()
+ {
+ std::vector<std::string> exp;
+ std::vector<std::string> act;
+
+ //
+ // gcc
+ //
+ exp = { "-o", "foo" };
+ act = ld_option(ctor::toolchain::gcc, ctor::ld_opt::output, "foo");
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "-s" };
+ act = ld_option(ctor::toolchain::gcc, ctor::ld_opt::strip);
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "-Wall" };
+ act = ld_option(ctor::toolchain::gcc, ctor::ld_opt::warn_all);
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "-Werror" };
+ act = ld_option(ctor::toolchain::gcc, ctor::ld_opt::warnings_as_errors);
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "-Lfoo" };
+ act = ld_option(ctor::toolchain::gcc, ctor::ld_opt::library_path, "foo");
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "-lfoo" };
+ act = ld_option(ctor::toolchain::gcc, ctor::ld_opt::link, "foo");
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "-std=foo" };
+ act = ld_option(ctor::toolchain::gcc, ctor::ld_opt::cpp_std, "foo");
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "-shared" };
+ act = ld_option(ctor::toolchain::gcc, ctor::ld_opt::build_shared);
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "-pthread" };
+ act = ld_option(ctor::toolchain::gcc, ctor::ld_opt::threads);
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "-fPIC" };
+ act = ld_option(ctor::toolchain::gcc, ctor::ld_opt::position_independent_code);
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "-fPIE" };
+ act = ld_option(ctor::toolchain::gcc, ctor::ld_opt::position_independent_executable);
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "-foo" };
+ act = ld_option(ctor::toolchain::gcc, ctor::ld_opt::custom, "-foo");
+ uASSERT_EQUAL(exp, act);
+
+ //
+ // clang
+ //
+ exp = { "-o", "foo" };
+ act = ld_option(ctor::toolchain::clang, ctor::ld_opt::output, "foo");
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "-s" };
+ act = ld_option(ctor::toolchain::clang, ctor::ld_opt::strip);
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "-Wall" };
+ act = ld_option(ctor::toolchain::clang, ctor::ld_opt::warn_all);
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "-Werror" };
+ act = ld_option(ctor::toolchain::clang, ctor::ld_opt::warnings_as_errors);
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "-Lfoo" };
+ act = ld_option(ctor::toolchain::clang, ctor::ld_opt::library_path, "foo");
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "-lfoo" };
+ act = ld_option(ctor::toolchain::clang, ctor::ld_opt::link, "foo");
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "-std=foo" };
+ act = ld_option(ctor::toolchain::clang, ctor::ld_opt::cpp_std, "foo");
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "-shared" };
+ act = ld_option(ctor::toolchain::clang, ctor::ld_opt::build_shared);
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "-pthread" };
+ act = ld_option(ctor::toolchain::clang, ctor::ld_opt::threads);
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "-fPIC" };
+ act = ld_option(ctor::toolchain::clang, ctor::ld_opt::position_independent_code);
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "-fPIE" };
+ act = ld_option(ctor::toolchain::clang, ctor::ld_opt::position_independent_executable);
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "-foo" };
+ act = ld_option(ctor::toolchain::clang, ctor::ld_opt::custom, "-foo");
+ uASSERT_EQUAL(exp, act);
+
+ //
+ // any
+ //
+ exp = { "{ctor::ld_opt::output, \"foo\"}" };
+ act = ld_option(ctor::toolchain::any, ctor::ld_opt::output, "foo");
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "{ctor::ld_opt::strip}" };
+ act = ld_option(ctor::toolchain::any, ctor::ld_opt::strip);
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "{ctor::ld_opt::warn_all}" };
+ act = ld_option(ctor::toolchain::any, ctor::ld_opt::warn_all);
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "{ctor::ld_opt::warnings_as_errors}" };
+ act = ld_option(ctor::toolchain::any, ctor::ld_opt::warnings_as_errors);
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "{ctor::ld_opt::library_path, \"foo\"}" };
+ act = ld_option(ctor::toolchain::any, ctor::ld_opt::library_path, "foo");
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "{ctor::ld_opt::link, \"foo\"}" };
+ act = ld_option(ctor::toolchain::any, ctor::ld_opt::link, "foo");
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "{ctor::ld_opt::cpp_std, \"foo\"}" };
+ act = ld_option(ctor::toolchain::any, ctor::ld_opt::cpp_std, "foo");
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "{ctor::ld_opt::build_shared}" };
+ act = ld_option(ctor::toolchain::any, ctor::ld_opt::build_shared);
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "{ctor::ld_opt::threads}" };
+ act = ld_option(ctor::toolchain::any, ctor::ld_opt::threads);
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "{ctor::ld_opt::position_independent_code}" };
+ act = ld_option(ctor::toolchain::any, ctor::ld_opt::position_independent_code);
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "{ctor::ld_opt::position_independent_executable}" };
+ act = ld_option(ctor::toolchain::any, ctor::ld_opt::position_independent_executable);
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "{ctor::ld_opt::custom, \"-foo\"}" };
+ act = ld_option(ctor::toolchain::any, ctor::ld_opt::custom, "-foo");
+ uASSERT_EQUAL(exp, act);
+ }
+
+ void getOption_toolchain_ar_test()
+ {
+ std::vector<std::string> exp;
+ std::vector<std::string> act;
+
+ //
+ // gcc
+ //
+ exp = { "-r" };
+ act = ar_option(ctor::toolchain::gcc, ctor::ar_opt::replace);
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "-s" };
+ act = ar_option(ctor::toolchain::gcc, ctor::ar_opt::add_index);
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "-c" };
+ act = ar_option(ctor::toolchain::gcc, ctor::ar_opt::create);
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "foo" };
+ act = ar_option(ctor::toolchain::gcc, ctor::ar_opt::output, "foo");
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "-foo" };
+ act = ar_option(ctor::toolchain::gcc, ctor::ar_opt::custom, "-foo");
+ uASSERT_EQUAL(exp, act);
+
+ //
+ // clang
+ //
+ exp = { "-r" };
+ act = ar_option(ctor::toolchain::clang, ctor::ar_opt::replace);
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "-s" };
+ act = ar_option(ctor::toolchain::clang, ctor::ar_opt::add_index);
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "-c" };
+ act = ar_option(ctor::toolchain::clang, ctor::ar_opt::create);
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "foo" };
+ act = ar_option(ctor::toolchain::clang, ctor::ar_opt::output, "foo");
+ uASSERT_EQUAL(exp, act);
+
+ exp = { "-foo" };
+ act = ar_option(ctor::toolchain::clang, ctor::ar_opt::custom, "-foo");
+ uASSERT_EQUAL(exp, act);
+
+ //
+ // any
+ //
+ exp = { "{ctor::ar_opt::custom, \"-foo\"}" };
+ act = ar_option(ctor::toolchain::any, ctor::ar_opt::custom, "-foo");
+ uASSERT_EQUAL(exp, act);
+}
+
+ void getOption_toolchain_asm_test()
+ {
+ std::vector<std::string> exp;
+ std::vector<std::string> act;
+
+ //
+ // gcc
+ //
+ exp = { "-foo" };
+ act = asm_option(ctor::toolchain::gcc, ctor::asm_opt::custom, "-foo");
+ uASSERT_EQUAL(exp, act);
+
+ //
+ // clang
+ //
+ exp = { "-foo" };
+ act = asm_option(ctor::toolchain::clang, ctor::asm_opt::custom, "-foo");
+ uASSERT_EQUAL(exp, act);
+
+ //
+ // any
+ //
+ exp = { "{ctor::asm_opt::custom, \"-foo\"}" };
+ act = asm_option(ctor::toolchain::any, ctor::asm_opt::custom, "-foo");
+ uASSERT_EQUAL(exp, act);
+ }
+
+
+ void getOption_str_c_test()
+ {
+ ctor::c_flag exp("");
+ ctor::c_flag act("");
+
+ //
+ // gcc
+ //
+ exp = { ctor::c_opt::include_path, "foo" };
+ act = c_option("-Ifoo", ctor::toolchain::gcc);
+ uASSERT_EQUAL(exp, act);
+
+ exp = { ctor::c_opt::custom, "foo" };
+ act = c_option("foo", ctor::toolchain::gcc);
+ uASSERT_EQUAL(exp, act);
+
+ //
+ // clang
+ //
+ exp = { ctor::c_opt::include_path, "foo" };
+ act = c_option("-Ifoo", ctor::toolchain::clang);
+ uASSERT_EQUAL(exp, act);
+
+ exp = { ctor::c_opt::custom, "foo" };
+ act = c_option("foo", ctor::toolchain::clang);
+ uASSERT_EQUAL(exp, act);
+ }
+
+ void getOption_str_cxx_test()
+ {
+ ctor::cxx_flag exp("");
+ ctor::cxx_flag act("");
+
+ //
+ // gcc
+ //
+ exp = { ctor::cxx_opt::include_path, "foo" };
+ act = cxx_option("-Ifoo", ctor::toolchain::gcc);
+ uASSERT_EQUAL(exp, act);
+
+ exp = { ctor::cxx_opt::custom, "foo" };
+ act = cxx_option("foo", ctor::toolchain::gcc);
+ uASSERT_EQUAL(exp, act);
+
+ //
+ // clang
+ //
+ exp = { ctor::cxx_opt::include_path, "foo" };
+ act = cxx_option("-Ifoo", ctor::toolchain::clang);
+ uASSERT_EQUAL(exp, act);
+
+ exp = { ctor::cxx_opt::custom, "foo" };
+ act = cxx_option("foo", ctor::toolchain::clang);
+ uASSERT_EQUAL(exp, act);
+ }
+
+ void getOption_str_ld_test()
+ {
+ ctor::ld_flag exp("");
+ ctor::ld_flag act("");
+
+ //
+ // gcc
+ //
+ exp = { ctor::ld_opt::library_path, "foo" };
+ act = ld_option("-Lfoo", ctor::toolchain::gcc);
+ uASSERT_EQUAL(exp, act);
+
+ exp = { ctor::ld_opt::custom, "foo" };
+ act = ld_option("foo", ctor::toolchain::gcc);
+ uASSERT_EQUAL(exp, act);
+
+ //
+ // clang
+ //
+ exp = { ctor::ld_opt::library_path, "foo" };
+ act = ld_option("-Lfoo", ctor::toolchain::clang);
+ uASSERT_EQUAL(exp, act);
+
+ exp = { ctor::ld_opt::custom, "foo" };
+ act = ld_option("foo", ctor::toolchain::clang);
+ uASSERT_EQUAL(exp, act);
+ }
+
+ void getOption_str_ar_test()
+ {
+ ctor::ar_flag exp("");
+ ctor::ar_flag act("");
+
+ //
+ // gcc
+ //
+ exp = { ctor::ar_opt::custom, "foo" };
+ act = ar_option("foo", ctor::toolchain::gcc);
+ uASSERT_EQUAL(exp, act);
+
+ //
+ // clang
+ //
+ exp = { ctor::ar_opt::custom, "foo" };
+ act = ar_option("foo", ctor::toolchain::clang);
+ uASSERT_EQUAL(exp, act);
+ }
+
+ void getOption_str_asm_test()
+ {
+ ctor::asm_flag exp("");
+ ctor::asm_flag act("");
+
+ //
+ // gcc
+ //
+ exp = { ctor::asm_opt::custom, "foo" };
+ act = asm_option("foo", ctor::toolchain::gcc);
+ uASSERT_EQUAL(exp, act);
+
+ //
+ // clang
+ //
+ exp = { ctor::asm_opt::custom, "foo" };
+ act = asm_option("foo", ctor::toolchain::clang);
+ uASSERT_EQUAL(exp, act);
+ }
+
+
+ void to_strings_c_test()
+ {
+ std::vector<std::string> exp;
+ std::vector<std::string> act;
+
+ // Mismatching toolchain (required vs actual) results in no output
+ // otherwise to_strings is just a proxy for c_option
+ act = to_strings(ctor::toolchain::gcc, {ctor::toolchain::clang, ctor::c_opt::no_link});
+ uASSERT_EQUAL(exp, act);
+ }
+
+ void to_strings_cxx_test()
+ {
+ std::vector<std::string> exp;
+ std::vector<std::string> act;
+
+ // Mismatching toolchain (required vs actual) results in no output
+ // otherwise to_strings is just a proxy for cxx_option
+ act = to_strings(ctor::toolchain::gcc, {ctor::toolchain::clang, ctor::cxx_opt::no_link});
+ uASSERT_EQUAL(exp, act);
+ }
+
+ void to_strings_ld_test()
+ {
+ std::vector<std::string> exp;
+ std::vector<std::string> act;
+
+ // Mismatching toolchain (required vs actual) results in no output
+ // otherwise to_strings is just a proxy for ld_option
+ act = to_strings(ctor::toolchain::gcc, {ctor::toolchain::clang, ctor::ld_opt::strip});
+ uASSERT_EQUAL(exp, act);
+ }
+
+ void to_strings_ar_test()
+ {
+ std::vector<std::string> exp;
+ std::vector<std::string> act;
+
+ // Mismatching toolchain (required vs actual) results in no output
+ // otherwise to_strings is just a proxy for ar_option
+ act = to_strings(ctor::toolchain::gcc, {ctor::toolchain::clang, ctor::ar_opt::custom, "foo"});
+ uASSERT_EQUAL(exp, act);
+ }
+
+ void to_strings_asm_test()
+ {
+ std::vector<std::string> exp;
+ std::vector<std::string> act;
+
+ // Mismatching toolchain (required vs actual) results in no output
+ // otherwise to_strings is just a proxy for asm_option
+ act = to_strings(ctor::toolchain::gcc, {ctor::toolchain::clang, ctor::asm_opt::custom, "foo"});
+ uASSERT_EQUAL(exp, act);
+ }
+};
+
+// Registers the fixture into the 'registry'
+static ToolsTest test;