summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/argparser.h477
-rw-r--r--src/build.cc2
-rw-r--r--src/configure.cc381
-rw-r--r--src/ctor.h349
-rw-r--r--src/execute.cc5
m---------src/getoptpp0
-rw-r--r--src/libctor.cc207
-rw-r--r--src/rebuild.cc139
-rw-r--r--src/rebuild.h18
-rw-r--r--src/task.cc19
-rw-r--r--src/task.h6
-rw-r--r--src/task_ar.cc29
-rw-r--r--src/task_ar.h4
-rw-r--r--src/task_cc.cc19
-rw-r--r--src/task_cc.h3
-rw-r--r--src/task_fn.cc187
-rw-r--r--src/task_fn.h8
-rw-r--r--src/task_ld.cc41
-rw-r--r--src/task_ld.h5
-rw-r--r--src/task_so.cc35
-rw-r--r--src/task_so.h4
-rw-r--r--src/tasks.cc65
-rw-r--r--src/tasks.h3
-rw-r--r--src/tools.cc151
-rw-r--r--src/tools.h34
-rw-r--r--src/util.cc54
-rw-r--r--src/util.h18
27 files changed, 1686 insertions, 577 deletions
diff --git a/src/argparser.h b/src/argparser.h
new file mode 100644
index 0000000..c5337e0
--- /dev/null
+++ b/src/argparser.h
@@ -0,0 +1,477 @@
+// -*- c++ -*-
+// Distributed under the BSD 2-Clause License.
+// See accompanying file LICENSE for details.
+#pragma once
+
+#include <functional>
+#include <variant>
+#include <optional>
+#include <string>
+#include <type_traits>
+#include <stdexcept>
+#include <iostream>
+#include <limits>
+
+namespace arg
+{
+struct noarg {};
+template<typename T>
+struct Opt
+{
+ char shortopt;
+ std::string longopt;
+ std::function<int(T)> cb;
+ std::string help;
+ T t{};
+};
+
+template<>
+struct Opt<noarg>
+{
+ char shortopt;
+ std::string longopt;
+ std::function<int()> cb;
+ std::string help;
+ noarg t{};
+};
+
+template<typename Callable, typename... Args>
+auto call_if(Callable cb, Args... args)
+{
+ using Ret = std::invoke_result_t<decltype(cb), Args&&...>;
+ if constexpr (std::is_same_v<Ret, void>)
+ {
+ if(cb)
+ {
+ return cb(std::forward<Args>(args)...);
+ }
+ }
+ else
+ {
+ if(cb)
+ {
+ return cb(std::forward<Args>(args)...);
+ }
+ return Ret{};
+ }
+}
+
+enum class error
+{
+ missing_arg,
+ invalid_arg,
+ invalid_opt,
+};
+
+template<typename... Ts>
+class Parser
+{
+public:
+ struct missing_arg{};
+
+ Parser(int argc_, const char* const* argv_)
+ : argc(argc_)
+ , argv(argv_)
+ {
+ }
+
+ int parse() const
+ {
+ bool demarcate{false};
+ for(int i = 1; i < argc; ++i) // skip argv[0] which is program name
+ {
+ std::string_view arg{argv[i]};
+ if(arg.size() == 0)
+ {
+ // Empty arg - This shouldn't happen
+ continue;
+ }
+
+ if(arg[0] != '-' || demarcate) // positional arg
+ {
+ auto res = call_if(pos_cb, arg);
+ if(res != 0)
+ {
+ return res;
+ }
+ continue;
+ }
+
+ if(arg == "--")
+ {
+ demarcate = true;
+ continue;
+ }
+
+ bool was_handled{false};
+ enum class state { handled, unhandled };
+
+ if(arg.size() > 1 && arg[0] == '-' && arg[1] == '-') // long
+ {
+ for(const auto& option : options)
+ {
+ auto ret =
+ std::visit([&](auto&& opt) -> std::pair<int, state>
+ {
+ if(opt.longopt != arg &&
+ !arg.starts_with(opt.longopt+'='))
+ {
+ return {0, state::unhandled};
+ }
+ try
+ {
+ using T = std::decay_t<decltype(opt)>;
+ if constexpr (std::is_same_v<T, Opt<noarg>>)
+ {
+ return {opt.cb(), state::handled};
+ }
+ else
+ {
+ return {opt.cb(convert(i, opt.t)),
+ state::handled};
+ }
+ }
+ catch(std::invalid_argument&)
+ {
+ call_if(err_cb, error::invalid_arg, argv[i]);
+ return {1, state::handled};
+ }
+ catch(missing_arg&)
+ {
+ call_if(err_cb, error::missing_arg, argv[i]);
+ return {1, state::handled};
+ }
+ }, option);
+ if(ret.second == state::handled && ret.first != 0)
+ {
+ return ret.first;
+ }
+ was_handled |= ret.second == state::handled;
+ if(was_handled)
+ {
+ break;
+ }
+ }
+ }
+ else
+ if(arg.size() > 1 && arg[0] == '-') // short
+ {
+ for(auto index = 1u; index < arg.size(); ++index)
+ {
+ was_handled = false;
+ for(const auto& option : options)
+ {
+ auto ret =
+ std::visit([&](auto&& opt) -> std::pair<int, state>
+ {
+ char c = arg[index];
+ if(opt.shortopt != c)
+ {
+ return {0, state::unhandled};
+ }
+ try
+ {
+ using T = std::decay_t<decltype(opt)>;
+ if constexpr (std::is_same_v<T, Opt<noarg>>)
+ {
+ return {opt.cb(), state::handled};
+ }
+ else
+ {
+ // Note: the rest of arg is converted to opt
+ auto idx = index;
+ // set index out of range all was eaten as arg
+ index = std::numeric_limits<int>::max();
+ return {opt.cb(convert_short(&arg[idx],
+ i, opt.t)),
+ state::handled};
+ }
+ }
+ catch(std::invalid_argument&)
+ {
+ call_if(err_cb, error::invalid_arg, argv[i]);
+ return {1, state::handled};
+ }
+ catch(missing_arg&)
+ {
+ call_if(err_cb, error::missing_arg, argv[i]);
+ return {1, state::handled};
+ }
+ }, option);
+ if(ret.second == state::handled && ret.first != 0)
+ {
+ return ret.first;
+ }
+ was_handled |= ret.second == state::handled;
+ if(was_handled)
+ {
+ break;
+ }
+ }
+ }
+ }
+
+ if(!was_handled)
+ {
+ call_if(err_cb, error::invalid_opt, arg);
+ return 1;
+ }
+ }
+ return 0;
+ }
+
+ template<typename T>
+ void add(char shortopt,
+ const std::string& longopt,
+ std::function<int(T)> cb,
+ const std::string& help)
+ {
+ options.emplace_back(Opt<T>{shortopt, longopt, cb, help});
+ }
+
+ void add(char shortopt,
+ const std::string& longopt,
+ std::function<int()> cb,
+ const std::string& help)
+ {
+ options.emplace_back(Opt<noarg>{shortopt, longopt, cb, help});
+ }
+
+ void set_pos_cb(std::function<int(std::string_view)> cb)
+ {
+ pos_cb = cb;
+ }
+
+ void set_err_cb(std::function<void(error, std::string_view)> cb)
+ {
+ err_cb = cb;
+ }
+
+ std::string prog_name() const
+ {
+ if(argc < 1)
+ {
+ return {};
+ }
+ return argv[0];
+ }
+
+ void help() const
+ {
+ constexpr std::size_t width{26};
+ constexpr std::size_t column_width{80};
+
+ for(const auto& option : options)
+ {
+ std::visit(
+ [&](auto&& opt)
+ {
+ std::string _args;
+ using T = std::decay_t<decltype(opt)>;
+ if constexpr (std::is_same_v<T, Opt<noarg>>)
+ {
+ }
+ else if constexpr (std::is_same_v<T, Opt<int>>)
+ {
+ _args = "<int>";
+ }
+ else if constexpr (std::is_same_v<T, Opt<std::optional<int>>>)
+ {
+ _args = "[int]";
+ }
+ else if constexpr (std::is_same_v<T, Opt<std::string>>)
+ {
+ _args = "<str>";
+ }
+ else if constexpr (std::is_same_v<T, Opt<std::optional<std::string>>>)
+ {
+ _args = "[str]";
+ }
+ else if constexpr (std::is_same_v<T, Opt<double>>)
+ {
+ _args = "<real>";
+ }
+ else if constexpr (std::is_same_v<T, Opt<std::optional<double>>>)
+ {
+ _args = "[real]";
+ }
+ else
+ {
+ static_assert(std::is_same_v<T, void>, "missing");
+ }
+
+ std::string option_str;
+ if(opt.shortopt != '\0' && !opt.longopt.empty())
+ {
+ option_str = " -" + std::string(1, opt.shortopt) + ", " +
+ opt.longopt + " " + _args;
+ }
+ else if(opt.shortopt != '\0')
+ {
+ option_str = " -" + std::string(1, opt.shortopt) + _args;
+ }
+ else if(!opt.longopt.empty())
+ {
+ option_str = " " + std::string(opt.longopt) + " " + _args;
+ }
+
+ std::string padding;
+ if(option_str.size() < width)
+ {
+ padding.append(width - option_str.size(), ' ');
+ }
+ else
+ {
+ padding = "\n";
+ padding.append(width, ' ');
+ }
+
+ std::cout << option_str << padding;
+
+ auto i = width;
+ for(auto c : opt.help)
+ {
+ if((c == '\n') || (i > column_width && (c == ' ' || c == '\t')))
+ {
+ std::string _padding(width, ' ');
+ std::cout << '\n' << _padding;
+ i = width;
+ continue;
+ }
+ std::cout << c;
+ ++i;
+ }
+ std::cout << '\n';
+ }, option);
+ }
+ }
+
+private:
+ template<typename T>
+ T convert(int& i, T) const
+ {
+ auto opt = convert(i, std::optional<T>{});
+ if(!opt)
+ {
+ throw missing_arg{};
+ }
+ return *opt;
+ }
+
+ template<typename T>
+ std::optional<T> convert(int& i, std::optional<T>) const
+ {
+ std::string arg;
+ bool has_arg{false};
+ std::string opt = argv[i];
+ if(opt.starts_with("--"))
+ {
+ // long opt
+ auto equals_pos = opt.find('=');
+ if(equals_pos != std::string::npos)
+ {
+ arg = opt.substr(equals_pos + 1);
+ has_arg = true;
+ }
+ else if(i+1 < argc)
+ {
+ arg = argv[i+1];
+ has_arg = !arg.starts_with("-");
+ if(has_arg)
+ {
+ ++i;
+ }
+ }
+ }
+
+ if(!has_arg)
+ {
+ return {};
+ }
+
+ if constexpr (std::is_same_v<T, int>)
+ {
+ return std::stoi(arg);
+ }
+ else if constexpr (std::is_same_v<T, double>)
+ {
+ return std::stod(arg);
+ }
+ else if constexpr (std::is_same_v<T, std::string>)
+ {
+ return arg;
+ }
+ else
+ {
+ static_assert(std::is_same_v<T, void>, "missing");
+ }
+ return {};
+ }
+
+ template<typename T>
+ T convert_short(const char* arg_, int& i, T) const
+ {
+ auto opt = convert_short(arg_, i, std::optional<T>{}, false);
+ if(!opt)
+ {
+ throw missing_arg{};
+ }
+ return *opt;
+ }
+
+ template<typename T>
+ std::optional<T> convert_short(const char* arg_, int& i,
+ std::optional<T>, bool optional = true) const
+ {
+ std::string arg;
+ bool has_arg{false};
+ std::string opt = arg_;
+ if(opt.length() > 1)
+ {
+ // arg in same token
+ arg = opt.substr(1);
+ has_arg = true;
+ }
+ else if(!optional && i+1 < argc)
+ {
+ arg = argv[i+1];
+ has_arg = true;//!arg.starts_with("-");
+ if(has_arg)
+ {
+ ++i;
+ }
+ }
+
+ if(!has_arg)
+ {
+ return {};
+ }
+
+ if constexpr (std::is_same_v<T, int>)
+ {
+ return std::stoi(arg);
+ }
+ else if constexpr (std::is_same_v<T, double>)
+ {
+ return std::stod(arg);
+ }
+ else if constexpr (std::is_same_v<T, std::string>)
+ {
+ return arg;
+ }
+ else
+ {
+ static_assert(std::is_same_v<T, void>, "missing");
+ }
+ return {};
+ }
+
+ using Opts = std::variant<Opt<noarg>, Opt<Ts>...>;
+ std::vector<Opts> options;
+ std::function<int(std::string_view)> pos_cb;
+ int argc;
+ const char* const* argv;
+ std::function<void(error, std::string_view)> err_cb;
+};
+
+} // arg::
diff --git a/src/build.cc b/src/build.cc
index a31f6a5..5995fb7 100644
--- a/src/build.cc
+++ b/src/build.cc
@@ -65,7 +65,7 @@ int build(const ctor::settings& settings,
break;
}
- auto task = getNextTask(all_tasks, dirtyTasks);
+ auto task = getNextTask(settings, all_tasks, dirtyTasks);
if(task == nullptr)
{
if(processes.empty() && !dirtyTasks.empty())
diff --git a/src/configure.cc b/src/configure.cc
index a43152f..5ba87c3 100644
--- a/src/configure.cc
+++ b/src/configure.cc
@@ -6,10 +6,11 @@
#include <iostream>
#include <filesystem>
#include <fstream>
+#include <sstream>
#include <optional>
#include <span>
-
-#include <getoptpp/getoptpp.hpp>
+#include <cstring>
+#include <functional>
#include "execute.h"
#include "ctor.h"
@@ -18,6 +19,7 @@
#include "externals.h"
#include "tools.h"
#include "util.h"
+#include "argparser.h"
const std::filesystem::path configurationFile("configuration.cc");
const std::filesystem::path configHeaderFile("config.h");
@@ -25,18 +27,36 @@ const std::filesystem::path configHeaderFile("config.h");
std::map<std::string, std::string> external_includedir;
std::map<std::string, std::string> external_libdir;
-const ctor::configuration& __attribute__((weak)) ctor::get_configuration()
+std::function<const ctor::configuration&()>& getConfigurationCallback()
+{
+ static std::function<const ctor::configuration&()> configuration_callback;
+ return configuration_callback;
+}
+
+namespace ctor {
+int reg(std::function<const ctor::configuration&()> cb,
+ [[maybe_unused]]const std::source_location location)
+{
+ auto& configuration_callback = getConfigurationCallback();
+ configuration_callback = cb;
+ return {};
+}
+} // ctor::
+
+const ctor::configuration& ctor::get_configuration()
{
+ auto& configuration_callback = getConfigurationCallback();
+ if(configuration_callback)
+ {
+ return configuration_callback();
+ }
+
static ctor::configuration cfg;
static bool initialised{false};
if(!initialised)
{
std::string cxx_prog{"c++"};
- auto cxx_env = std::getenv("CXX");
- if(cxx_env)
- {
- cxx_prog = cxx_env;
- }
+ get_env("CXX", cxx_prog);
cfg.build_toolchain = getToolChain(cfg.get(ctor::cfg::build_cxx, cxx_prog));
@@ -100,11 +120,32 @@ std::string ctor::configuration::get(const std::string& key,
return ctor::conf_values[key];
}
- if(has(key))
+ if(tools.find(key) != tools.end())
{
return tools.at(key);
}
+ std::string value;
+ if(key == ctor::cfg::build_cxx && get_env("CXX", value))
+ {
+ return value;
+ }
+
+ if(key == ctor::cfg::build_cc && get_env("CC", value))
+ {
+ return value;
+ }
+
+ if(key == ctor::cfg::build_ld && get_env("LD", value))
+ {
+ return value;
+ }
+
+ if(key == ctor::cfg::build_ar && get_env("AR", value))
+ {
+ return value;
+ }
+
return default_value;
}
@@ -116,10 +157,9 @@ std::string ctor::configuration::getenv(const std::string& key) const
return envit->second;
}
- auto sysenv = std::getenv(key.data());
- if(sysenv)
+ if(std::string value; get_env(key.data(), value))
{
- return sysenv;
+ return value;
}
return {};
@@ -132,20 +172,16 @@ public:
Args(const std::vector<std::string>& args)
{
resize(args.size() + 1);
- (*this)[0] = strdup("./ctor");
+ owning_container.push_back("./ctor");
+ (*this)[0] = owning_container.back().data();
for(std::size_t i = 0; i < size() - 1; ++i)
{
- (*this)[i + 1] = strdup(args[i].data());
+ owning_container.push_back(args[i]);
+ (*this)[i + 1] = owning_container.back().data();
}
}
- ~Args()
- {
- for(std::size_t i = 0; i < size(); ++i)
- {
- free((*this)[i]);
- }
- }
+ std::deque<std::string> owning_container;
};
namespace {
@@ -236,8 +272,7 @@ int regenerateCache(ctor::settings& settings,
{
Args vargs(args);
- dg::Options opt;
- int key{128};
+ arg::Parser<std::string> opt(static_cast<int>(vargs.size()), vargs.data());
std::string build_arch_prefix;
std::string build_path;
@@ -251,97 +286,110 @@ int regenerateCache(ctor::settings& settings,
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;
+ opt.add('b', "--build-dir",
+ std::function([&](std::string arg)
+ {
+ settings.builddir = arg;
+ builddir = arg;
return 0;
- });
+ }),
+ "Set output directory for build files (default: '" +
+ settings.builddir + "').");
- opt.add("verbose", no_argument, 'v',
- "Be verbose. Add multiple times for more verbosity.",
- [&]() {
+ opt.add('v', "--verbose",
+ std::function([&]()
+ {
settings.verbose++;
return 0;
- });
+ }),
+ "Be verbose. Add multiple times for more verbosity.");
- opt.add("cc", required_argument, key++,
- "Use specified c-compiler instead of gcc.",
- [&]() {
- cc_prog = optarg;
+ opt.add({}, "--cc",
+ std::function([&](std::string arg)
+ {
+ cc_prog = arg;
return 0;
- });
+ }),
+ "Use specified c-compiler instead of gcc.");
- opt.add("cxx", required_argument, key++,
- "Use specified c++-compiler instead of g++.",
- [&]() {
- cxx_prog = optarg;
+ opt.add({}, "--cxx",
+ std::function([&](std::string arg)
+ {
+ cxx_prog = arg;
return 0;
- });
+ }),
+ "Use specified c++-compiler instead of g++.");
- opt.add("ar", required_argument, key++,
- "Use specified archiver instead of ar.",
- [&]() {
- ar_prog = optarg;
+ opt.add({}, "--ar",
+ std::function([&](std::string arg)
+ {
+ ar_prog = arg;
return 0;
- });
+ }),
+ "Use specified archiver instead of ar.");
- opt.add("ld", required_argument, key++,
- "Use specified linker instead of ld.",
- [&]() {
- ld_prog = optarg;
+ opt.add({}, "--ld",
+ std::function([&](std::string arg)
+ {
+ ld_prog = arg;
return 0;
- });
+ }),
+ "Use specified linker instead of ld.");
- opt.add("build", required_argument, key++,
- "Configure for building on specified architecture.",
- [&]() {
- build_arch_prefix = optarg;
+ opt.add({}, "--build",
+ std::function([&](std::string arg)
+ {
+ build_arch_prefix = arg;
return 0;
- });
+ }),
+ "Configure for building on specified architecture.");
- opt.add("build-path", required_argument, key++,
- "Set path to build tool-chain.",
- [&]() {
- build_path = optarg;
+ opt.add({}, "--build-path",
+ std::function([&](std::string arg)
+ {
+ build_path = arg;
return 0;
- });
+ }),
+ "Set path to build tool-chain.");
- opt.add("host", required_argument, key++,
- "Cross-compile to build programs to run on specified architecture.",
- [&]() {
- host_arch_prefix = optarg;
+ opt.add({}, "--host",
+ std::function([&](std::string arg)
+ {
+ host_arch_prefix = arg;
return 0;
- });
+ }),
+ "Cross-compile to build programs to run on specified architecture.");
- opt.add("host-path", required_argument, key++,
- "Set path to cross-compile tool-chain.",
- [&]() {
- host_path = optarg;
+ opt.add({}, "--host-path",
+ std::function([&](std::string arg)
+ {
+ host_path = arg;
return 0;
- });
+ }),
+ "Set path to cross-compile tool-chain.");
- opt.add("ctor-includedir", required_argument, key++,
- "Set path to ctor header file, used for re-compiling.",
- [&]() {
- ctor_includedir = optarg;
+ opt.add({}, "--ctor-includedir",
+ std::function([&](std::string arg)
+ {
+ ctor_includedir = arg;
return 0;
- });
+ }),
+ "Set path to ctor header file, used for re-compiling.");
- opt.add("ctor-libdir", required_argument, key++,
- "Set path to ctor library file, used for re-compiling.",
- [&]() {
- ctor_libdir = optarg;
+ opt.add({}, "--ctor-libdir",
+ std::function([&](std::string arg)
+ {
+ ctor_libdir = arg;
return 0;
- });
+ }),
+ "Set path to ctor library file, used for re-compiling.");
// Resolv externals
ctor::external_configurations externalConfigs;
- for(std::size_t i = 0; i < numExternalConfigFiles; ++i)
+ const auto& externalConfigFiles = getExternalConfigFileList();
+ for(const auto& externalConfigFile : externalConfigFiles)
{
- auto newExternalConfigs = externalConfigFiles[i].cb(settings);
+ auto newExternalConfigs = externalConfigFile.cb(settings);
externalConfigs.insert(externalConfigs.end(),
newExternalConfigs.begin(),
newExternalConfigs.end());
@@ -350,19 +398,21 @@ int regenerateCache(ctor::settings& settings,
auto add_path_args =
[&](const std::string& arg_name)
{
- opt.add(arg_name + "-includedir", required_argument, key++,
- "Set path to " + arg_name + " header file.",
- [&]() {
- external_includedir[arg_name] = optarg;
+ opt.add({}, "--" + arg_name + "-includedir",
+ std::function([&](std::string arg)
+ {
+ external_includedir[arg_name] = arg;
return 0;
- });
+ }),
+ "Set path to " + arg_name + " header file.");
- opt.add(arg_name + "-libdir", required_argument, key++,
- "Set path to " + arg_name + " libraries.",
- [&]() {
- external_libdir[arg_name] = optarg;
+ opt.add({}, "--" + arg_name + "-libdir",
+ std::function([&](std::string arg)
+ {
+ external_libdir[arg_name] = arg;
return 0;
- });
+ }),
+ "Set path to " + arg_name + " libraries.");
};
for(const auto& ext : externalConfigs)
@@ -382,17 +432,57 @@ int regenerateCache(ctor::settings& settings,
}
- opt.add("help", no_argument, 'h',
- "Print this help text.",
- [&]() -> int {
+ opt.add('h', "--help",
+ std::function([&]() -> int
+ {
std::cout << "Configure how to build with " << name << "\n";
std::cout << "Usage: " << name << " configure [options]\n\n";
std::cout << "Options:\n";
opt.help();
exit(0);
- });
+ }),
+ "Print this help text.");
+
+ opt.set_err_cb(
+ [&](arg::error err, std::string_view arg)
+ {
+ switch(err)
+ {
+ case arg::error::invalid_arg:
+ std::cerr << opt.prog_name() <<
+ ": invalid argument for option '" << arg << "'\n";
+ std::cerr << "Type '" << opt.prog_name() <<
+ " -h' for more information.\n";
+ break;
- opt.process(static_cast<int>(vargs.size()), vargs.data());
+ case arg::error::missing_arg:
+ std::cerr << opt.prog_name() << ": option requires and argument '" <<
+ arg << "'\n";
+ std::cerr << "Type '" << opt.prog_name() <<
+ " -h' for more information.\n";
+ break;
+
+ case arg::error::invalid_opt:
+ std::cerr << opt.prog_name() << ": invalid option '" << arg << "'\n";
+ std::cerr << "Type '" << opt.prog_name() <<
+ " -h' for more information.\n";
+ break;
+ }
+ });
+
+ opt.set_pos_cb(
+ [&](std::string_view)
+ {
+ std::cerr <<
+ "The configure subcommand doesn't use positional arguments.\n";
+ return 1;
+ });
+
+ auto res = opt.parse();
+ if(res != 0)
+ {
+ return res;
+ }
if(host_arch_prefix.empty())
{
@@ -425,7 +515,8 @@ int regenerateCache(ctor::settings& settings,
{
case ctor::target_type::executable:
case ctor::target_type::unit_test:
- case ctor::target_type::dynamic_library:
+ case ctor::target_type::shared_library:
+ case ctor::target_type::module:
needs_build_ld = true;
break;
case ctor::target_type::static_library:
@@ -462,7 +553,8 @@ int regenerateCache(ctor::settings& settings,
{
case ctor::target_type::executable:
case ctor::target_type::unit_test:
- case ctor::target_type::dynamic_library:
+ case ctor::target_type::shared_library:
+ case ctor::target_type::module:
needs_host_ld = true;
break;
case ctor::target_type::static_library:
@@ -676,14 +768,14 @@ int regenerateCache(ctor::settings& settings,
{
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);
+ std::cout << "Generating configuration: " << configurationFile.string() << "\n"; {
+ std::stringstream istr;
istr << "#include <ctor.h>\n\n";
- istr << "const ctor::configuration& ctor::get_configuration()\n";
+ istr << "const ctor::configuration& stored_configuration()\n";
istr << "{\n";
istr << " static ctor::configuration cfg =\n";
istr << " {\n";
@@ -770,7 +862,7 @@ int regenerateCache(ctor::settings& settings,
for(const auto& ext : externalConfigs)
{
- istr << " { \"" << esc(ext.name) << "\", {\n";
+ istr << " { \"" << esc(ext.name) << "\", ctor::flags{\n";
ctor::flags resolved_flags;
if(std::holds_alternative<ctor::external_manual>(ext.external))
{
@@ -789,7 +881,7 @@ int regenerateCache(ctor::settings& settings,
if(!resolved_flags.cflags.empty())
{
- istr << " .cflags = {";
+ istr << " ctor::c_flags{";
for(const auto& flag : resolved_flags.cflags)
{
istr << flag << ",";
@@ -799,7 +891,7 @@ int regenerateCache(ctor::settings& settings,
if(!resolved_flags.cxxflags.empty())
{
- istr << " .cxxflags = {";
+ istr << " ctor::cxx_flags{";
for(const auto& flag : resolved_flags.cxxflags)
{
istr << flag << ",";
@@ -809,7 +901,7 @@ int regenerateCache(ctor::settings& settings,
if(!resolved_flags.ldflags.empty())
{
- istr << " .ldflags = {";
+ istr << " ctor::ld_flags{";
for(const auto& flag : resolved_flags.ldflags)
{
istr << flag << ",";
@@ -819,7 +911,7 @@ int regenerateCache(ctor::settings& settings,
if(!resolved_flags.asmflags.empty())
{
- istr << " .asmflags = {";
+ istr << " ctor::asm_flags{";
for(const auto& flag : resolved_flags.asmflags)
{
istr << flag << ",";
@@ -833,13 +925,29 @@ int regenerateCache(ctor::settings& settings,
istr << " };\n";
istr << " return cfg;\n";
istr << "}\n";
+ istr << "\nREG(stored_configuration);\n";
+
+ auto new_configuration = istr.str();
+ auto current_configuration = readFile(configurationFile.string());
+ if(current_configuration != new_configuration)
+ {
+ std::ofstream configuration_stream(configurationFile.string());
+ configuration_stream << new_configuration;
+ }
}
{
- std::ofstream istr(configHeaderFile);
- istr << "#pragma once\n\n";
- istr << "#define HAS_FOO 1\n";
- istr << "//#define HAS_BAR 1\n";
+ std::stringstream new_config_stream;
+ new_config_stream << "#pragma once\n\n";
+ new_config_stream << "#define HAS_FOO 1\n";
+ new_config_stream << "//#define HAS_BAR 1\n";
+ auto new_config = new_config_stream.str();
+ auto current_config_content = readFile(configHeaderFile.string());
+ if(current_config_content != new_config)
+ {
+ std::ofstream config_file_stream(configHeaderFile.string());
+ config_file_stream << new_config;
+ }
}
return 0;
@@ -858,52 +966,45 @@ int configure(const ctor::settings& global_settings, int argc, char* argv[])
}
std::map<std::string, std::string> env;
- auto cc_env = getenv("CC");
- if(cc_env)
+ std::string value;
+ if(get_env("CC", value))
{
- env["CC"] = cc_env;
+ env["CC"] = value;
}
- auto cflags_env = getenv("CFLAGS");
- if(cflags_env)
+ if(get_env("CFLAGS", value))
{
- env["CFLAGS"] = cflags_env;
+ env["CFLAGS"] = value;
}
- auto cxx_env = getenv("CXX");
- if(cxx_env)
+ if(get_env("CXX", value))
{
- env["CXX"] = cxx_env;
+ env["CXX"] = value;
}
- auto cxxflags_env = getenv("CXXFLAGS");
- if(cxxflags_env)
+ if(get_env("CXXFLAGS", value))
{
- env["CXXFLAGS"] = cxxflags_env;
+ env["CXXFLAGS"] = value;
}
- auto ar_env = getenv("AR");
- if(ar_env)
+ if(get_env("AR", value))
{
- env["AR"] = ar_env;
+ env["AR"] = value;
}
- auto ld_env = getenv("LD");
- if(ld_env)
+ if(get_env("LD", value))
{
- env["LD"] = ld_env;
+ env["LD"] = value;
}
- auto ldflags_env = getenv("LDFLAGS");
- if(ldflags_env)
+ if(get_env("LDFLAGS", value))
{
- env["LDFLAGS"] = ldflags_env;
+ env["LDFLAGS"] = value;
}
- auto path_env = getenv("PATH");
- if(path_env)
+ if(get_env("PATH", value))
{
- env["PATH"] = path_env;
+ env["PATH"] = value;
}
auto ret = regenerateCache(settings, args_span[0], args, env);
diff --git a/src/ctor.h b/src/ctor.h
index 6cb46a5..8a7c809 100644
--- a/src/ctor.h
+++ b/src/ctor.h
@@ -11,6 +11,7 @@
#include <cstddef>
#include <functional>
#include <string_view>
+#include <cassert>
namespace ctor {
@@ -20,7 +21,9 @@ enum class target_type
executable,
static_library,
- dynamic_library,
+ shared_library,
+ dynamic_library = shared_library,
+ module,
object,
unit_test,
unit_test_library,
@@ -61,27 +64,59 @@ enum class toolchain
clang,
};
-struct source
+struct output_file
{
- source(const char* file_) : file(file_) {} // convenience ctor
-
- source(std::string_view file_) : source(file_, ctor::language::automatic) {}
- source(std::string_view file_, ctor::language lang_) : file(file_), language(lang_) {}
-
- source(std::string_view file_, std::string_view output_) : file(file_), output(output_) {}
- source(std::string_view file_, ctor::language lang_, std::string_view output_) : file(file_), language(lang_), output(output_) {}
-
- source(ctor::toolchain toolchain_, std::string_view file_) : file(file_), toolchain(toolchain_) {}
- source(ctor::toolchain toolchain_, std::string_view file_, ctor::language lang_) : file(file_), toolchain(toolchain_), language(lang_) {}
+ std::string file;
+};
- source(ctor::toolchain toolchain_, std::string_view file_, std::string_view output_) : file(file_), toolchain(toolchain_), output(output_) {}
+enum class source_type
+{
+ regular,
+ generated,
+};
- source(ctor::toolchain toolchain_, std::string_view file_, ctor::language lang_, std::string_view output_) : file(file_), toolchain(toolchain_), language(lang_), output(output_) {}
+struct source
+{
+ template <class ... Args>
+ requires ((
+ std::is_convertible_v<Args, std::string_view> ||
+ std::is_same_v<Args, ctor::toolchain> ||
+ std::is_same_v<Args, ctor::language> ||
+ std::is_same_v<Args, ctor::source_type> ||
+ std::is_same_v<Args, ctor::output_file>
+ ) && ...)
+ constexpr source(Args && ... arg)
+ {
+ ([&]
+ {
+ if constexpr(std::is_convertible_v<Args, std::string_view>)
+ {
+ file = arg;
+ }
+ else if constexpr(std::is_same_v<Args, ctor::toolchain>)
+ {
+ toolchain = arg;
+ }
+ else if constexpr(std::is_same_v<Args, ctor::language>)
+ {
+ language = arg;
+ }
+ else if constexpr(std::is_same_v<Args, ctor::output_file>)
+ {
+ output = arg.file;
+ }
+ else if constexpr(std::is_same_v<Args, ctor::source_type>)
+ {
+ source_type = arg;
+ }
+ }(), ...);
+ }
std::string file;
ctor::toolchain toolchain{ctor::toolchain::any};
ctor::language language{ctor::language::automatic};
std::string output{};
+ ctor::source_type source_type{ctor::source_type::regular};
};
enum class cxx_opt
@@ -94,6 +129,7 @@ enum class cxx_opt
warn_shadow, // -Wshadow
warn_extra, // -Wextra
warnings_as_errors, // -Werror
+ exceptions, // -fexceptions
generate_dep_tree, // -MMD
no_link, // -c
include_path, // -I<arg>
@@ -163,24 +199,60 @@ template<typename T>
class flag
{
public:
- flag(std::string_view str);
- flag(const char* str);
- flag(T opt_) : opt(opt_) {}
- flag(T opt_, std::string_view arg_, std::string_view arg2_ = "")
- : opt(opt_), arg(arg_), arg2(arg2_) {}
- flag(T opt_, const char* arg_, const char* arg2_ = "")
- : opt(opt_), arg(arg_), arg2(arg2_) {}
- flag(ctor::toolchain toolchain_, T opt_)
- : toolchain(toolchain_), opt(opt_) {}
- flag(ctor::toolchain toolchain_, T opt_, const char* arg_, const char* arg2_ = "")
- : toolchain(toolchain_), opt(opt_), arg(arg_), arg2(arg2_) {}
- flag(ctor::toolchain toolchain_, T opt_, std::string_view arg_, std::string_view arg2_ = "")
- : toolchain(toolchain_), opt(opt_), arg(arg_), arg2(arg2_) {}
+ template <class ... Args>
+ requires ((
+ std::is_convertible_v<Args, std::string_view> ||
+ std::is_same_v<Args, ctor::toolchain> ||
+ std::is_same_v<Args, T>
+ ) && ...)
+ constexpr flag(Args && ... _arg)
+ {
+ constexpr std::size_t n = sizeof...(Args);
+ int state{}; // 0: opt, 1: arg1, 2: arg2, 3: error
+ ([&]
+ {
+ if constexpr(std::is_convertible_v<Args, std::string_view>)
+ {
+ if constexpr(n == 1)
+ {
+ std::string str(_arg);
+ to_flag(str);
+ }
+ else
+ {
+ assert(state > 0); // opt must be before args
+ if(state == 1)
+ {
+ this->arg = _arg;
+ }
+ else
+ {
+ assert(state == 2); // up to 2 args supported
+ this->arg2 = _arg;
+ }
+ ++state;
+ }
+ }
+ else if constexpr(std::is_same_v<Args, ctor::toolchain>)
+ {
+ toolchain = _arg;
+ }
+ else if constexpr(std::is_same_v<Args, T>)
+ {
+ assert(state == 0); // opt must be before args
+ opt = _arg;
+ ++state;
+ }
+ }(), ...);
+ }
ctor::toolchain toolchain{ctor::toolchain::any};
T opt{};
std::string arg;
std::string arg2;
+
+private:
+ void to_flag(std::string_view str);
};
using c_flag = ctor::flag<ctor::c_opt>;
@@ -197,6 +269,41 @@ using asm_flags = std::vector<ctor::asm_flag>;
struct flags
{
+ template <class ... Args>
+ requires ((
+ std::is_same_v<Args, ctor::c_flags> ||
+ std::is_same_v<Args, ctor::cxx_flags> ||
+ std::is_same_v<Args, ctor::ld_flags> ||
+ std::is_same_v<Args, ctor::ar_flags> ||
+ std::is_same_v<Args, ctor::asm_flags>
+ ) && ...)
+ constexpr flags(Args && ... arg)
+ {
+ ([&]
+ {
+ if constexpr(std::is_same_v<Args, ctor::c_flags>)
+ {
+ cflags = arg;
+ }
+ else if constexpr(std::is_same_v<Args, ctor::cxx_flags>)
+ {
+ cxxflags = arg;
+ }
+ else if constexpr(std::is_same_v<Args, ctor::ld_flags>)
+ {
+ ldflags = arg;
+ }
+ else if constexpr(std::is_same_v<Args, ctor::ar_flags>)
+ {
+ arflags = arg;
+ }
+ else if constexpr(std::is_same_v<Args, ctor::asm_flags>)
+ {
+ asmflags = arg;
+ }
+ }(), ...);
+ }
+
ctor::c_flags cflags; // flags for c compiler
ctor::cxx_flags cxxflags; // flags for c++ compiler
ctor::ld_flags ldflags; // flags for linker
@@ -209,16 +316,126 @@ struct settings
std::string builddir{"build"};
std::size_t parallel_processes{1};
int verbose{0}; // -1: completely silent, 0: normal, 1: verbose, ...
+ bool dry_run{false};
};
struct build_configuration;
-using GeneratorCb = std::function<int(const std::string& input,
- const std::string& output,
- const build_configuration& config,
- const ctor::settings& settings)>;
+using GeneratorOneToOne =
+ std::function<int(const std::string& input,
+ const std::string& output,
+ const build_configuration& config,
+ const ctor::settings& settings)>;
+
+using GeneratorManyToOne =
+ std::function<int(const std::vector<std::string>& input,
+ const std::string& output,
+ const ctor::build_configuration& config,
+ const ctor::settings& settings)>;
+
+struct name
+{
+ std::string name;
+};
+
+struct target
+{
+ std::string target;
+};
+
+using sources = std::vector<ctor::source>;
+
+struct depends
+{
+ std::vector<std::string> depends;
+};
+
+struct externals
+{
+ std::vector<std::string> externals;
+};
struct build_configuration
{
+ template <class ... Args>
+ requires ((
+ std::is_same_v<Args, ctor::name> ||
+ std::is_same_v<Args, ctor::target_type> ||
+ std::is_same_v<Args, ctor::output_system> ||
+ std::is_same_v<Args, ctor::target> ||
+ std::is_same_v<Args, ctor::sources> ||
+ std::is_same_v<Args, ctor::depends> ||
+ std::is_same_v<Args, ctor::externals> ||
+ std::is_convertible_v<Args, ctor::GeneratorOneToOne> ||
+ std::is_convertible_v<Args, ctor::GeneratorManyToOne> ||
+ std::is_same_v<Args, ctor::c_flags> ||
+ std::is_same_v<Args, ctor::cxx_flags> ||
+ std::is_same_v<Args, ctor::ld_flags> ||
+ std::is_same_v<Args, ctor::ar_flags> ||
+ std::is_same_v<Args, ctor::asm_flags>
+ ) && ...)
+ constexpr build_configuration(Args && ... arg)
+ {
+ ([&]
+ {
+ if constexpr(std::is_same_v<Args, ctor::name>)
+ {
+ name = arg.name;
+ }
+ else if constexpr(std::is_same_v<Args, ctor::target_type>)
+ {
+ type = arg;
+ }
+ else if constexpr(std::is_same_v<Args, ctor::output_system>)
+ {
+ system = arg;
+ }
+ else if constexpr(std::is_same_v<Args, ctor::target>)
+ {
+ target = arg.target;
+ }
+ else if constexpr(std::is_same_v<Args, ctor::sources>)
+ {
+ sources = arg;
+ }
+ else if constexpr(std::is_same_v<Args, ctor::depends>)
+ {
+ depends = arg.depends;
+ }
+ else if constexpr(std::is_same_v<Args, ctor::externals>)
+ {
+ externals = arg.externals;
+ }
+ else if constexpr(std::is_convertible_v<Args, ctor::GeneratorOneToOne>)
+ {
+ function_one_to_one = arg;
+ }
+ else if constexpr(std::is_convertible_v<Args, ctor::GeneratorManyToOne>)
+ {
+ function_many_to_one = arg;
+ }
+ else if constexpr(std::is_same_v<Args, ctor::c_flags>)
+ {
+ flags.cflags = arg;
+ }
+ else if constexpr(std::is_same_v<Args, ctor::cxx_flags>)
+ {
+ flags.cxxflags = arg;
+ }
+ else if constexpr(std::is_same_v<Args, ctor::ld_flags>)
+ {
+ flags.ldflags = arg;
+ }
+ else if constexpr(std::is_same_v<Args, ctor::ar_flags>)
+ {
+ flags.arflags = arg;
+ }
+ else if constexpr(std::is_same_v<Args, ctor::asm_flags>)
+ {
+ flags.asmflags = arg;
+ }
+ }(), ...);
+ }
+
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::build};
@@ -227,23 +444,84 @@ struct build_configuration
std::vector<std::string> depends; // internal target dependencies
ctor::flags flags;
std::vector<std::string> externals; // externals used by this configuration
- GeneratorCb function;
+ ctor::GeneratorOneToOne function_one_to_one;
+ ctor::GeneratorManyToOne function_many_to_one;
};
using build_configurations = std::vector<build_configuration>;
-int reg(ctor::build_configurations (*cb)(const ctor::settings&),
+int reg(std::function<ctor::build_configurations (const ctor::settings&)> cb,
const std::source_location location = std::source_location::current());
// This type will use flags verbatim
struct external_manual
{
+ template <class ... Args>
+ requires ((
+ std::is_same_v<Args, ctor::c_flags> ||
+ std::is_same_v<Args, ctor::cxx_flags> ||
+ std::is_same_v<Args, ctor::ld_flags> ||
+ std::is_same_v<Args, ctor::ar_flags> ||
+ std::is_same_v<Args, ctor::asm_flags>
+ ) && ...)
+ constexpr external_manual(Args && ... arg)
+ {
+ ([&]
+ {
+ if constexpr(std::is_same_v<Args, ctor::c_flags>)
+ {
+ flags.cflags = arg;
+ }
+ else if constexpr(std::is_same_v<Args, ctor::cxx_flags>)
+ {
+ flags.cxxflags = arg;
+ }
+ else if constexpr(std::is_same_v<Args, ctor::ld_flags>)
+ {
+ flags.ldflags = arg;
+ }
+ else if constexpr(std::is_same_v<Args, ctor::ar_flags>)
+ {
+ flags.arflags = arg;
+ }
+ else if constexpr(std::is_same_v<Args, ctor::asm_flags>)
+ {
+ flags.asmflags = arg;
+ }
+ }(), ...);
+ }
+
ctor::flags flags;
};
struct external_configuration
{
+ template <class ... Args>
+ requires ((
+ std::is_same_v<Args, ctor::name> ||
+ std::is_same_v<Args, ctor::output_system> ||
+ std::is_same_v<Args, ctor::external_manual>
+ ) && ...)
+ constexpr external_configuration(Args && ... arg)
+ {
+ ([&]
+ {
+ if constexpr(std::is_same_v<Args, ctor::name>)
+ {
+ name = arg.name;
+ }
+ else if constexpr(std::is_same_v<Args, ctor::output_system>)
+ {
+ system = arg;
+ }
+ else if constexpr(std::is_same_v<Args, ctor::external_manual>)
+ {
+ external = arg;
+ }
+ }(), ...);
+ }
+
std::string name; // Name for configuration
ctor::output_system system{ctor::output_system::build};
std::variant<ctor::external_manual> external;
@@ -251,7 +529,7 @@ struct external_configuration
using external_configurations = std::vector<ctor::external_configuration>;
-int reg(ctor::external_configurations (*cb)(const ctor::settings&),
+int reg(std::function<ctor::external_configurations (const ctor::settings&)> cb,
const std::source_location location = std::source_location::current());
// Convenience macro - ugly but keeps things simple(r)
@@ -301,4 +579,7 @@ struct configuration
const ctor::configuration& get_configuration();
+int reg(std::function<const ctor::configuration&()> cb,
+ const std::source_location location = std::source_location::current());
+
} // ctor::
diff --git a/src/execute.cc b/src/execute.cc
index ad6c2a2..c050732 100644
--- a/src/execute.cc
+++ b/src/execute.cc
@@ -107,7 +107,10 @@ int execute(const ctor::settings& settings,
{
envmap.insert(key + "=" + value);
}
-
+ if(settings.dry_run)
+ {
+ _exit(0);
+ }
auto [_, envv] = envmap.get();
execve(command.data(), const_cast<char* const *>(argv.data()),
const_cast<char* const *>(envv));
diff --git a/src/getoptpp b/src/getoptpp
deleted file mode 160000
-Subproject 5aba94355ec638c6f8612f86be309ed684979ae
diff --git a/src/libctor.cc b/src/libctor.cc
index aaf17c9..2685ec0 100644
--- a/src/libctor.cc
+++ b/src/libctor.cc
@@ -17,14 +17,14 @@
#include <cstdlib>
#include <span>
-#include <getoptpp/getoptpp.hpp>
-
#include "ctor.h"
#include "configure.h"
#include "rebuild.h"
#include "tasks.h"
#include "build.h"
#include "unittest.h"
+#include "argparser.h"
+#include "util.h"
int main(int argc, char* argv[])
{
@@ -58,108 +58,120 @@ int main(int argc, char* argv[])
bool list_targets{false};
bool no_relaunch{false}; // true means no re-launch after rebuild.
bool run_unittests{false};
-
- dg::Options opt;
- int key{128};
-
- opt.add("jobs", required_argument, 'j',
- "Number of parallel jobs. (default: cpucount * 2 - 1)",
- [&]() {
- try
- {
- settings.parallel_processes =
- static_cast<std::size_t>(std::stoi(optarg));
- }
- catch(...)
- {
- std::cerr << "Not a number\n";
- return 1;
- }
+ std::vector<std::string> arguments;
+ arg::Parser<int, std::string> opt(argc, argv);
+ opt.set_pos_cb(
+ [&](std::string_view arg)
+ {
+ arguments.emplace_back(std::string(arg));
+ return 0;
+ });
+
+ opt.add('j', "--jobs",
+ std::function([&](int jobs)
+ {
+ settings.parallel_processes = static_cast<std::size_t>(jobs);
return 0;
- });
+ }),
+ "Number of parallel jobs. (default: cpucount * 2 - 1)");
- opt.add("build-dir", required_argument, 'b',
- "Overload output directory for build files (default: '" +
- settings.builddir + "').",
- [&]() {
- settings.builddir = optarg;
+ opt.add('b', "--build-dir",
+ std::function([&](std::string builddir) {
+ settings.builddir = builddir;
return 0;
- });
+ }),
+ "Overload output directory for build files (default: '" +
+ settings.builddir + "').");
- opt.add("verbose", no_argument, 'v',
- "Be verbose. Add multiple times for more verbosity.",
- [&]() {
+ opt.add('v', "--verbose",
+ std::function([&]()
+ {
settings.verbose++;
return 0;
- });
+ }),
+ "Be verbose. Add multiple times for more verbosity.");
- opt.add("quiet", no_argument, 'q',
- "Be completely silent.",
- [&]() {
+ opt.add('q', "--quiet",
+ std::function([&]() {
settings.verbose = -1;
return 0;
- });
+ }),
+ "Be completely silent.");
- opt.add("add", required_argument, 'a',
- "Add specified file to the build configurations.",
- [&]() {
+ opt.add('a', "--add",
+ std::function([&](std::string filename) {
no_relaunch = true;
- add_files.emplace_back(optarg);
+ add_files.emplace_back(filename);
return 0;
- });
+ }),
+ "Add specified file to the build configurations.");
- opt.add("remove", required_argument, 'r',
- "Remove specified file from the build configurations.",
- [&]() {
+ opt.add('r', "--remove",
+ std::function([&](std::string filename)
+ {
no_relaunch = true;
- remove_files.emplace_back(optarg);
+ remove_files.emplace_back(filename);
return 0;
- });
+ }),
+ "Remove specified file from the build configurations.");
- opt.add("list-files", no_argument, 'L',
- "List files in the build configurations.",
- [&]() {
+ opt.add('L', "--list-files",
+ std::function([&]()
+ {
no_relaunch = true;
list_files = true;
return 0;
- });
+ }),
+ "List files in the build configurations.");
- opt.add("list-targets", no_argument, 'l',
- "List targets.",
- [&]() {
+ opt.add('l', "--list-targets",
+ std::function([&]()
+ {
no_relaunch = true;
list_targets = true;
return 0;
- });
+ }),
+ "List targets.");
+
+ opt.add('n', "--dry-run",
+ std::function([&]()
+ {
+ settings.dry_run = true;
+ return 0;
+ }),
+ "Print the commands to be executed, but do not execute them.");
- opt.add("configure-cmd", no_argument, key++,
- "Print commandline for last configure.",
- [&]() {
+ opt.add({}, "--configure-cmd",
+ std::function([&]()
+ {
no_relaunch = true;
print_configure_cmd = true;
return 0;
- });
+ }),
+ "Print commandline for last configure.");
- opt.add("configure-db", no_argument, key++,
- "Print entire configure parameter database.",
- [&]() {
+ opt.add({}, "--configure-db",
+ std::function([&]()
+ {
no_relaunch = true;
print_configure_db = true;
return 0;
- });
+ }),
+ "Print entire configure parameter database.");
- opt.add("database", required_argument, 'd',
- "Write compilation database json file.",
- [&]() {
+ opt.add('d', "--database",
+ std::function([&](std::string database)
+ {
no_relaunch = true;
write_compilation_database = true;
- compilation_database = optarg;
+ compilation_database = database;
return 0;
- });
+ }),
+ "Write compilation database json file.");
- opt.add("help", no_argument, 'h',
- "Print this help text.",
- [&]() -> int {
+ opt.add('h', "--help",
+ std::function([&]() -> int
+ {
std::cout << "Usage: " << args[0] << " [options] [target] ...\n";
std::cout <<
R"_( where target can be either:
@@ -174,28 +186,67 @@ Options:
)_";
opt.help();
exit(0);
- });
+ }),
+ "Print this help text.");
- opt.process(argc, argv);
+ opt.set_err_cb(
+ [&](arg::error err, std::string_view arg)
+ {
+ switch(err)
+ {
+ case arg::error::invalid_arg:
+ std::cerr << opt.prog_name() <<
+ ": invalid argument for option '" << arg << "'\n";
+ std::cerr << "Type '" << opt.prog_name() <<
+ " -h' for more information.\n";
+ break;
+
+ case arg::error::missing_arg:
+ std::cerr << opt.prog_name() << ": option requires and argument '" <<
+ arg << "'\n";
+ std::cerr << "Type '" << opt.prog_name() <<
+ " -h' for more information.\n";
+ break;
+
+ case arg::error::invalid_opt:
+ std::cerr << opt.prog_name() << ": invalid option '" << arg << "'\n";
+ std::cerr << "Type '" << opt.prog_name() <<
+ " -h' for more information.\n";
+ break;
+ }
+ });
+ auto res = opt.parse();
+ if(res != 0)
+ {
+ return res;
+ }
- auto verbose_env = std::getenv("V");
- if(verbose_env)
+ if(std::string value; get_env("V", value))
{
- settings.verbose = std::atoi(verbose_env);
+ try
+ {
+ settings.verbose = std::stoi(value);
+ }
+ catch(...)
+ {
+ // not an integer
+ }
}
if(list_files)
{
no_default_build = true;
std::vector<std::string> files;
- for(std::size_t i = 0; i < numConfigFiles; ++i)
+ const auto& configFiles = getConfigFileList();
+ for(const auto& configFile : configFiles)
{
- files.emplace_back(configFiles[i].file);
+ files.emplace_back(configFile.file);
}
- for(std::size_t i = 0; i < numExternalConfigFiles; ++i)
+ const auto& externalConfigFiles = getExternalConfigFileList();
+ for(const auto& externalConfigFile : externalConfigFiles)
{
- files.emplace_back(externalConfigFiles[i].file);
+ files.emplace_back(externalConfigFile.file);
}
std::sort(files.begin(), files.end());
@@ -288,7 +339,7 @@ Options:
}
bool build_all{!no_default_build};
- for(const auto& arg : opt.arguments())
+ for(const auto& arg : arguments)
{
if(arg == "configure")
{
diff --git a/src/rebuild.cc b/src/rebuild.cc
index a2b7ddd..d62e998 100644
--- a/src/rebuild.cc
+++ b/src/rebuild.cc
@@ -9,6 +9,7 @@
#include <source_location>
#include <cstring>
#include <span>
+#include <vector>
#include "configure.h"
#include "ctor.h"
@@ -18,34 +19,38 @@
#include "tools.h"
#include "util.h"
-std::array<BuildConfigurationEntry, 1024> configFiles;
-std::size_t numConfigFiles{0};
+std::vector<BuildConfigurationEntry>& getConfigFileList()
+{
+ static std::vector<BuildConfigurationEntry> configFiles;
+ return configFiles;
+}
+
+std::vector<ExternalConfigurationEntry>& getExternalConfigFileList()
+{
+ static std::vector<ExternalConfigurationEntry> externalConfigFiles;
+ return externalConfigFiles;
+}
namespace ctor {
-int reg(ctor::build_configurations (*cb)(const ctor::settings&),
+int reg(std::function<ctor::build_configurations (const ctor::settings&)> cb,
const std::source_location location)
{
- // NOTE: std::cout cannot be used here
- if(numConfigFiles >= configFiles.size())
- {
- fprintf(stderr, "Max %d build configurations currently supported.\n",
- (int)configFiles.size());
- exit(1);
- }
+ BuildConfigurationEntry entry;
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
+ entry.file = rel.string();
}
else
{
- configFiles[numConfigFiles].file = location.file_name();
+ entry.file = location.file_name();
}
- configFiles[numConfigFiles].cb = cb;
- ++numConfigFiles;
+ entry.cb = cb;
+ auto& configFiles = getConfigFileList();
+ configFiles.push_back(entry);
return 0;
}
@@ -53,80 +58,50 @@ int reg(ctor::build_configurations (*cb)(const ctor::settings&),
int reg(const char* location)
{
- // NOTE: std::cout cannot be used here
- if(numConfigFiles >= configFiles.size())
- {
- fprintf(stderr, "Max %d build configurations currently supported.\n",
- (int)configFiles.size());
- exit(1);
- }
+ BuildConfigurationEntry entry;
- configFiles[numConfigFiles].file = location;
- configFiles[numConfigFiles].cb =
- [](const ctor::settings&){ return std::vector<ctor::build_configuration>{}; };
- ++numConfigFiles;
+ entry.file = location;
+ entry.cb =
+ [](const ctor::settings&)
+ {
+ return std::vector<ctor::build_configuration>{};
+ };
+ auto& configFiles = getConfigFileList();
+ configFiles.push_back(entry);
return 0;
}
int unreg(const char* location)
{
- int found{0};
- for(std::size_t i = 0; i < numConfigFiles;)
- {
- if(std::string(location) == configFiles[i].file)
- {
- ++found;
- for(std::size_t j = i; j < numConfigFiles; ++j)
- {
- configFiles[j] = configFiles[j + 1];
- }
- --numConfigFiles;
- }
- else
- {
- ++i;
- }
- }
-
- for(std::size_t i = 0; i < numExternalConfigFiles;)
- {
- if(std::string(location) == externalConfigFiles[i].file)
- {
- ++found;
- for(std::size_t j = i; j < numExternalConfigFiles; ++j)
- {
- externalConfigFiles[j] = externalConfigFiles[j + 1];
- }
- --numExternalConfigFiles;
- }
- else
- {
- ++i;
- }
- }
-
- return found;
+ auto& configFiles = getConfigFileList();
+ auto erasedConfigs =
+ std::erase_if(configFiles,
+ [&](const BuildConfigurationEntry& entry)
+ {
+ return entry.file == location;
+ });
+
+ auto& externalConfigFiles = getExternalConfigFileList();
+ auto erasedExternals =
+ std::erase_if(externalConfigFiles,
+ [&](const ExternalConfigurationEntry& entry)
+ {
+ return entry.file == location;
+ });
+
+ return static_cast<int>(erasedConfigs) + static_cast<int>(erasedExternals);
}
-std::array<ExternalConfigurationEntry, 1024> externalConfigFiles;
-std::size_t numExternalConfigFiles{0};
-
namespace ctor {
-int reg(ctor::external_configurations (*cb)(const ctor::settings&),
+int reg(std::function<ctor::external_configurations (const ctor::settings&)> cb,
const std::source_location location)
{
- // NOTE: std::cout cannot be used here
- if(numExternalConfigFiles >= externalConfigFiles.size())
- {
- fprintf(stderr, "Max %d external configurations currently supported.\n",
- (int)externalConfigFiles.size());
- exit(1);
- }
-
- externalConfigFiles[numExternalConfigFiles].file = location.file_name();
- externalConfigFiles[numExternalConfigFiles].cb = cb;
- ++numExternalConfigFiles;
+ ExternalConfigurationEntry entry;
+ entry.file = location.file_name();
+ entry.cb = cb;
+ auto& externalConfigFiles = getExternalConfigFileList();
+ externalConfigFiles.push_back(entry);
return 0;
}
@@ -155,9 +130,10 @@ bool recompileCheck(const ctor::settings& global_settings, int argc, char* argv[
using namespace std::string_literals;
+ const auto& configFiles = getConfigFileList();
if(global_settings.verbose > 1)
{
- std::cout << "Recompile check (" << numConfigFiles << "):\n";
+ std::cout << "Recompile check (" << configFiles.size() << "):\n";
}
ctor::build_configuration config;
@@ -201,9 +177,9 @@ bool recompileCheck(const ctor::settings& global_settings, int argc, char* argv[
config.sources.emplace_back(configurationFile.string());
}
- for(std::size_t i = 0; i < numConfigFiles; ++i)
+ for(const auto& configFile : configFiles)
{
- std::string location = configFiles[i].file;
+ std::string location = configFile.file;
if(global_settings.verbose > 1)
{
std::cout << " - " << location << "\n";
@@ -216,9 +192,10 @@ bool recompileCheck(const ctor::settings& global_settings, int argc, char* argv[
}
}
- for(std::size_t i = 0; i < numExternalConfigFiles; ++i)
+ const auto& externalConfigFiles = getExternalConfigFileList();
+ for(const auto& externalConfigFile : externalConfigFiles)
{
- std::string location = externalConfigFiles[i].file;
+ std::string location = externalConfigFile.file;
if(global_settings.verbose > 1)
{
std::cout << " - " << location << "\n";
diff --git a/src/rebuild.h b/src/rebuild.h
index efa6d42..8e0c78a 100644
--- a/src/rebuild.h
+++ b/src/rebuild.h
@@ -5,26 +5,26 @@
#include <vector>
#include <array>
+#include <string>
+#include <functional>
#include "ctor.h"
struct BuildConfigurationEntry
{
- const char* file;
- ctor::build_configurations (*cb)(const ctor::settings&);
+ std::string file;
+ std::function<ctor::build_configurations (const ctor::settings&)> cb;
};
+std::vector<BuildConfigurationEntry>& getConfigFileList();
+
struct ExternalConfigurationEntry
{
- const char* file;
- ctor::external_configurations (*cb)(const ctor::settings&);
+ std::string file;
+ std::function<ctor::external_configurations (const ctor::settings&)> cb;
};
-extern std::array<BuildConfigurationEntry, 1024> configFiles;
-extern std::size_t numConfigFiles;
-
-extern std::array<ExternalConfigurationEntry, 1024> externalConfigFiles;
-extern std::size_t numExternalConfigFiles;
+std::vector<ExternalConfigurationEntry>& getExternalConfigFileList();
int reg(const char* location);
int unreg(const char* location);
diff --git a/src/task.cc b/src/task.cc
index ef7731b..3a7b895 100644
--- a/src/task.cc
+++ b/src/task.cc
@@ -7,18 +7,31 @@
#include <algorithm>
#include <utility>
-Task::Task(const ctor::build_configuration& config_, const ctor::settings& settings_,
+Task::Task(ctor::target_type resolved_target_type,
+ const ctor::build_configuration& config_,
+ const ctor::settings& settings_,
std::string sourceDir_)
: config(config_)
, output_system(config.system)
, settings(settings_)
- , sourceDir(std::move(sourceDir_))
+ , sourceDir(sourceDir_)
{
+ assert(resolved_target_type != ctor::target_type::automatic);
+ target_type = resolved_target_type;
+ output_system = config.system;
}
int Task::registerDepTasks(const std::vector<std::shared_ptr<Task>>& tasks)
{
- for(const auto& depStr : depends())
+ auto dependsList = depends();
+ if(!derived())
+ {
+ for(const auto& dep : config.depends)
+ {
+ dependsList.emplace_back(dep);
+ }
+ }
+ for(const auto& depStr : dependsList)
{
bool found{false};
for(const auto& task : tasks)
diff --git a/src/task.h b/src/task.h
index 32d0de3..f26d217 100644
--- a/src/task.h
+++ b/src/task.h
@@ -23,7 +23,9 @@ enum class State
class Task
{
public:
- Task(const ctor::build_configuration& config, const ctor::settings& settings,
+ Task(ctor::target_type resolved_target_type,
+ const ctor::build_configuration& config,
+ const ctor::settings& settings,
std::string sourceDir);
virtual ~Task() = default;
@@ -79,5 +81,5 @@ protected:
ctor::language source_language{ctor::language::automatic};
ctor::output_system output_system{ctor::output_system::host};
const ctor::settings& settings;
- std::string sourceDir;
+ std::filesystem::path sourceDir;
};
diff --git a/src/task_ar.cc b/src/task_ar.cc
index 3b45cc2..4123a81 100644
--- a/src/task_ar.cc
+++ b/src/task_ar.cc
@@ -11,20 +11,18 @@
#include "util.h"
#include "tools.h"
-TaskAR::TaskAR(const ctor::build_configuration& config_,
+TaskAR::TaskAR(ctor::target_type resolved_target_type,
+ const ctor::build_configuration& config_,
const ctor::settings& settings_,
const std::string& target,
const std::vector<std::string>& objects,
const std::string& sourceDir_)
- : Task(config_, settings_, sourceDir_)
+ : Task(resolved_target_type, config_, settings_, sourceDir_)
, _targetFile(target)
, config(config_)
, settings(settings_)
, sourceDir(sourceDir_)
{
- target_type = ctor::target_type::static_library;
- output_system = config.system;
-
auto toolchain = getToolChain(config.system);
_targetFile = extension(toolchain, target_type, config.system, _targetFile);
for(const auto& object : objects)
@@ -34,11 +32,6 @@ TaskAR::TaskAR(const ctor::build_configuration& config_,
dependsStr.push_back(objectFile.string());
}
- for(const auto& dep : config.depends)
- {
- depFiles.emplace_back(dep);
- }
-
flagsFile = std::filesystem::path(settings.builddir) / cleanUp(sourceDir) / targetFile().stem();
flagsFile += ".flags";
@@ -77,6 +70,15 @@ bool TaskAR::dirtyInner()
}
}
+ auto target_file_time = std::filesystem::last_write_time(targetFile());
+ for(const auto& object_file : objectFiles)
+ {
+ if(std::filesystem::last_write_time(object_file) > target_file_time)
+ {
+ return true;
+ }
+ }
+
return false;
}
@@ -155,11 +157,6 @@ std::vector<std::string> TaskAR::depends() const
deps.push_back(objectFile.string());
}
- for(const auto& dep : config.depends)
- {
- deps.push_back(dep);
- }
-
return deps;
}
@@ -198,7 +195,7 @@ std::string TaskAR::flagsString() const
for(const auto& dep : config.depends)
{
- if(dep != config.depends[0])
+ if(&dep != &config.depends[0])
{
flagsStr += " ";
}
diff --git a/src/task_ar.h b/src/task_ar.h
index 601afeb..2bb7735 100644
--- a/src/task_ar.h
+++ b/src/task_ar.h
@@ -14,7 +14,8 @@ class TaskAR
: public Task
{
public:
- TaskAR(const ctor::build_configuration& config,
+ TaskAR(ctor::target_type resolved_target_type,
+ const ctor::build_configuration& config,
const ctor::settings& settings,
const std::string& target,
const std::vector<std::string>& objects,
@@ -37,7 +38,6 @@ private:
std::string flagsString() const;
std::vector<std::filesystem::path> objectFiles;
- std::vector<std::filesystem::path> depFiles;
std::filesystem::path _targetFile;
std::filesystem::path flagsFile;
diff --git a/src/task_cc.cc b/src/task_cc.cc
index 9628455..479a453 100644
--- a/src/task_cc.cc
+++ b/src/task_cc.cc
@@ -14,15 +14,22 @@
#include "tools.h"
#include "deps.h"
-TaskCC::TaskCC(const ctor::build_configuration& config_, const ctor::settings& settings_,
- const std::string& sourceDir_, const ctor::source& source)
- : Task(config_, settings_, sourceDir_)
+TaskCC::TaskCC(ctor::target_type resolved_target_type,
+ const ctor::build_configuration& config_,
+ const ctor::settings& settings_,
+ const std::string& sourceDir_,
+ const ctor::source& source)
+ : Task(resolved_target_type, config_, settings_, sourceDir_)
, sourceFile(sourceDir_)
, config(config_)
, settings(settings_)
, sourceDir(sourceDir_)
, _source(source)
{
+ if(source.source_type == ctor::source_type::generated)
+ {
+ sourceFile = std::filesystem::path(settings.builddir) / sourceFile;
+ }
sourceFile /= source.file;
std::filesystem::path base = sourceFile.parent_path();
@@ -31,8 +38,6 @@ TaskCC::TaskCC(const ctor::build_configuration& config_, const ctor::settings& s
base += "-";
base += sourceFile.stem();
- target_type = ctor::target_type::object;
- output_system = config.system;
source_language = source.language;
if(source_language == ctor::language::automatic)
{
@@ -252,6 +257,10 @@ int TaskCC::clean()
std::vector<std::string> TaskCC::depends() const
{
+ if(_source.source_type == ctor::source_type::generated)
+ {
+ return {sourceFile.string()};
+ }
return {};
}
diff --git a/src/task_cc.h b/src/task_cc.h
index 2299fcd..1312417 100644
--- a/src/task_cc.h
+++ b/src/task_cc.h
@@ -14,7 +14,8 @@ class TaskCC
: public Task
{
public:
- TaskCC(const ctor::build_configuration& config,
+ TaskCC(ctor::target_type resolved_target_type,
+ const ctor::build_configuration& config,
const ctor::settings& settings,
const std::string& sourceDir, const ctor::source& source);
virtual ~TaskCC() = default;
diff --git a/src/task_fn.cc b/src/task_fn.cc
index b6b50ea..4f27cc7 100644
--- a/src/task_fn.cc
+++ b/src/task_fn.cc
@@ -11,45 +11,129 @@
#include "execute.h"
#include "util.h"
-TaskFn::TaskFn(const ctor::build_configuration& config_, const ctor::settings& settings_,
- const std::string& sourceDir_, const ctor::source& source)
- : Task(config_, settings_, sourceDir_)
- , sourceFile(sourceDir_)
+TaskFn::TaskFn(ctor::target_type resolved_target_type,
+ const ctor::build_configuration& config_,
+ const ctor::settings& settings_,
+ const std::string& sourceDir_,
+ const ctor::source& source)
+ : Task(resolved_target_type, config_, settings_, sourceDir_)
, config(config_)
, settings(settings_)
{
- sourceFile /= source.file;
-
- std::filesystem::create_directories(std::filesystem::path(settings.builddir) / sourceFile.parent_path());
-
- target_type = config.type;
+ std::filesystem::create_directories(std::filesystem::path(settings.builddir) /
+ sourceDir.parent_path());
source_language = source.language;
- if(source.output.empty())
+ if(config.function_one_to_one)
{
- std::cerr << "Missing output file for functional target\n";
- exit(1);
+ if(source.source_type == ctor::source_type::generated)
+ {
+ sourceFile = std::filesystem::path(settings.builddir);
+ }
+ sourceFile /= sourceDir / source.file;
+
+ std::filesystem::path base = sourceFile.parent_path();
+
+ if(source.output.empty())
+ {
+ std::cerr << "Missing target/output file for functional target.\n";
+ exit(1);
+ }
+ _targetFile = base / source.output;
}
+ else if(config.function_many_to_one)
+ {
+ for(const auto& src : config.sources)
+ {
+ std::filesystem::path _src;
+ if(src.source_type == ctor::source_type::generated)
+ {
+ _src = std::filesystem::path(settings.builddir);
+ }
+ _src /= sourceDir / src.file;
+ sources.push_back(_src.string());
+ }
- _targetFile = source.output;
+ std::filesystem::path base = sourceDir;
+ if(config.target.empty())
+ {
+ std::cerr << "Missing target file for functional target\n";
+ exit(1);
+ }
+ _targetFile = base / config.target;
+ sourceListFile = targetFile().parent_path() / targetFile().filename();
+ sourceListFile += ".sources";
+ }
}
bool TaskFn::dirtyInner()
{
- if(!std::filesystem::exists(sourceFile))
+ if(!std::filesystem::exists(targetFile()))
{
- //std::cout << "Missing source file: " << std::string(sourceFile) << "\n";
+ //std::cout << "Missing targetFile\n";
return true;
}
- if(!std::filesystem::exists(targetFile()))
+ if(config.function_many_to_one)
+ {
+ if(!std::filesystem::exists(sourceListFile))
+ {
+ //std::cout << "Missing sourceListFile\n";
+ return true;
+ }
+
+ {
+ auto lastSourceList = readFile(sourceListFile.string());
+ if(sourceListString() != lastSourceList)
+ {
+ //std::cout << "The compiler sourceList changed\n";
+ return true;
+ }
+ }
+ }
+
+ std::filesystem::file_time_type last_changed{};
+ bool missing{false};
+ if(config.function_one_to_one)
+ {
+ if(!std::filesystem::exists(sourceFile))
+ {
+ missing = true;
+ }
+ last_changed = std::filesystem::last_write_time(sourceFile);
+ }
+ else if(config.function_many_to_one)
+ {
+ bool first{true};
+ for(const auto& source : sources)
+ {
+ if(!std::filesystem::exists(source))
+ {
+ missing |= true;
+ }
+ else
+ {
+ if(first)
+ {
+ last_changed = std::filesystem::last_write_time(source);
+ }
+ else
+ {
+ last_changed =
+ std::max(last_changed,
+ std::filesystem::last_write_time(source));
+ }
+ }
+ first = false;
+ }
+ }
+
+ if(missing)
{
- //std::cout << "Missing targetFile\n";
return true;
}
- if(std::filesystem::last_write_time(sourceFile) >
- std::filesystem::last_write_time(targetFile()))
+ if(last_changed > std::filesystem::last_write_time(targetFile()))
{
//std::cout << "The targetFile older than sourceFile\n";
return true;
@@ -60,10 +144,11 @@ bool TaskFn::dirtyInner()
int TaskFn::runInner()
{
- if(!std::filesystem::exists(sourceFile))
+ if(config.function_many_to_one)
{
- std::cout << "Missing source file: " << sourceFile.string() << "\n";
- return 1;
+ // Write sourceList to file.
+ std::ofstream sourceListStream(sourceListFile.string());
+ sourceListStream << sourceListString();
}
if(settings.verbose >= 0)
@@ -74,10 +159,24 @@ int TaskFn::runInner()
std::cout << output << std::flush;
}
- auto res = config.function(sourceFile.string(),
- targetFile().string(),
- config,
- settings);
+ int res{};
+ if(config.function_one_to_one)
+ {
+ auto func = config.function_one_to_one;
+ res = func(sourceFile.string(),
+ targetFile().string(),
+ config,
+ settings);
+ }
+ else if(config.function_many_to_one)
+ {
+ auto func = config.function_many_to_one;
+ res = func(sources,
+ targetFile().string(),
+ config,
+ settings);
+ }
+
if(res != 0)
{
std::filesystem::remove(targetFile());
@@ -94,12 +193,34 @@ int TaskFn::clean()
std::filesystem::remove(targetFile());
}
+ if(config.function_many_to_one)
+ {
+ if(std::filesystem::exists(sourceListFile))
+ {
+ std::cout << "Removing " << sourceListFile.string() << "\n";
+ std::filesystem::remove(sourceListFile);
+ }
+ }
+
return 0;
}
std::vector<std::string> TaskFn::depends() const
{
- return {};
+ std::vector<std::string> deps;
+ if(config.function_many_to_one)
+ {
+ for(const auto& src : config.sources)
+ {
+ if(src.source_type == ctor::source_type::generated)
+ {
+ std::filesystem::path _src = std::filesystem::path(settings.builddir);
+ _src /= src.file;
+ deps.push_back(_src.string());
+ }
+ }
+ }
+ return deps;
}
std::string TaskFn::target() const
@@ -109,7 +230,17 @@ std::string TaskFn::target() const
std::filesystem::path TaskFn::targetFile() const
{
- return std::filesystem::path(settings.builddir) / sourceDir / _targetFile;
+ return std::filesystem::path(settings.builddir) / _targetFile;
+}
+
+std::string TaskFn::sourceListString() const
+{
+ std::string sourceListStr;
+ for(const auto& source : config.sources)
+ {
+ sourceListStr += " " + source.file;
+ }
+ return sourceListStr;
}
bool TaskFn::derived() const
diff --git a/src/task_fn.h b/src/task_fn.h
index 1bad32c..e8cc5ce 100644
--- a/src/task_fn.h
+++ b/src/task_fn.h
@@ -14,7 +14,8 @@ class TaskFn
: public Task
{
public:
- TaskFn(const ctor::build_configuration& config,
+ TaskFn(ctor::target_type resolved_target_type,
+ const ctor::build_configuration& config,
const ctor::settings& settings,
const std::string& sourceDir, const ctor::source& source);
virtual ~TaskFn() = default;
@@ -28,6 +29,7 @@ public:
std::string target() const override;
std::filesystem::path targetFile() const override;
+ std::string sourceListString() const;
bool derived() const override;
std::string toJSON() const override;
@@ -37,8 +39,10 @@ public:
protected:
std::filesystem::path sourceFile;
std::filesystem::path _targetFile;
+ std::filesystem::path sourceListFile;
const ctor::build_configuration& config;
const ctor::settings& settings;
- std::filesystem::path sourceDir;
+
+ std::vector<std::string> sources;
};
diff --git a/src/task_ld.cc b/src/task_ld.cc
index 03745be..2dceb59 100644
--- a/src/task_ld.cc
+++ b/src/task_ld.cc
@@ -11,26 +11,18 @@
#include "util.h"
#include "tools.h"
-TaskLD::TaskLD(const ctor::build_configuration& config_,
+TaskLD::TaskLD(ctor::target_type resolved_target_type,
+ const ctor::build_configuration& config_,
const ctor::settings& settings_,
const std::string& target,
const std::vector<std::string>& objects,
const std::string& sourceDir_,
bool is_self_)
- : Task(config_, settings_, sourceDir_)
+ : Task(resolved_target_type, config_, settings_, sourceDir_)
, config(config_)
, settings(settings_)
- , sourceDir(sourceDir_)
, is_self(is_self_)
{
- target_type = config.type;
- output_system = config.system;
-
- if(target_type == ctor::target_type::automatic)
- {
- target_type = ctor::target_type::executable;
- }
-
_targetFile = target;
auto toolchain = getToolChain(config.system);
_targetFile = extension(toolchain, target_type, config.system, _targetFile);
@@ -40,13 +32,8 @@ TaskLD::TaskLD(const ctor::build_configuration& config_,
objectFiles.push_back(objectFile);
dependsStr.push_back(objectFile.string());
}
-
- for(const auto& dep : config.depends)
- {
- depFiles.emplace_back(dep);
- }
-
- flagsFile = std::filesystem::path(settings.builddir) / cleanUp(sourceDir) / targetFile().stem();
+ auto cleaned_source_dir = cleanUp(sourceDir.string());
+ flagsFile = std::filesystem::path(settings.builddir) / cleaned_source_dir / targetFile().stem();
flagsFile += ".flags";
source_language = ctor::language::c;
@@ -83,6 +70,15 @@ bool TaskLD::dirtyInner()
}
}
+ auto target_file_time = std::filesystem::last_write_time(targetFile());
+ for(const auto& object_file : objectFiles)
+ {
+ if(std::filesystem::last_write_time(object_file) > target_file_time)
+ {
+ return true;
+ }
+ }
+
return false;
}
@@ -95,7 +91,7 @@ int TaskLD::runInner()
{
auto depFile = dep->targetFile();
auto dep_type = target_type_from_extension(toolchain, depFile);
- if(dep_type == ctor::target_type::dynamic_library)
+ if(dep_type == ctor::target_type::shared_library)
{
append(args, ld_option(toolchain, ctor::ld_opt::library_path,
targetFile().parent_path().string()));
@@ -168,11 +164,6 @@ std::vector<std::string> TaskLD::depends() const
deps.push_back(objectFile.string());
}
- for(const auto& depFile : depFiles)
- {
- deps.push_back(depFile.string());
- }
-
return deps;
}
@@ -211,7 +202,7 @@ std::string TaskLD::flagsString() const
for(const auto& dep : config.depends)
{
- if(dep != config.depends[0])
+ if(&dep != &config.depends[0])
{
flagsStr += " ";
}
diff --git a/src/task_ld.h b/src/task_ld.h
index c0e3ebb..d9156b2 100644
--- a/src/task_ld.h
+++ b/src/task_ld.h
@@ -14,7 +14,8 @@ class TaskLD
: public Task
{
public:
- TaskLD(const ctor::build_configuration& config,
+ TaskLD(ctor::target_type resolved_target_type,
+ const ctor::build_configuration& config,
const ctor::settings& settings,
const std::string& target,
const std::vector<std::string>& objects,
@@ -38,12 +39,10 @@ private:
std::string flagsString() const;
std::vector<std::filesystem::path> objectFiles;
- std::vector<std::filesystem::path> depFiles;
std::filesystem::path _targetFile;
std::filesystem::path flagsFile;
const ctor::build_configuration& config;
const ctor::settings& settings;
- std::string sourceDir;
bool is_self;
};
diff --git a/src/task_so.cc b/src/task_so.cc
index 92aeefe..e1ea6af 100644
--- a/src/task_so.cc
+++ b/src/task_so.cc
@@ -11,22 +11,18 @@
#include "util.h"
#include "tools.h"
-TaskSO::TaskSO(const ctor::build_configuration& config_,
+TaskSO::TaskSO(ctor::target_type resolved_target_type,
+ const ctor::build_configuration& config_,
const ctor::settings& settings_,
const std::string& target,
const std::vector<std::string>& objects,
const std::string& sourceDir_)
- : Task(config_, settings_, sourceDir_)
+ : Task(resolved_target_type, config_, settings_, sourceDir_)
+ , _targetFile(target)
, config(config_)
, settings(settings_)
, sourceDir(sourceDir_)
{
- std::filesystem::path base = sourceDir;
-
- target_type = ctor::target_type::dynamic_library;
- output_system = config.system;
-
- _targetFile = base / target;
auto toolchain = getToolChain(config.system);
_targetFile = extension(toolchain, target_type, config.system, _targetFile);
for(const auto& object : objects)
@@ -36,11 +32,6 @@ TaskSO::TaskSO(const ctor::build_configuration& config_,
dependsStr.push_back(objectFile.string());
}
- for(const auto& dep : config.depends)
- {
- depFiles.emplace_back(dep);
- }
-
flagsFile = std::filesystem::path(settings.builddir) / cleanUp(sourceDir) / targetFile().stem();
flagsFile += ".flags";
@@ -79,6 +70,15 @@ bool TaskSO::dirtyInner()
}
}
+ auto target_file_time = std::filesystem::last_write_time(targetFile());
+ for(const auto& object_file : objectFiles)
+ {
+ if(std::filesystem::last_write_time(object_file) > target_file_time)
+ {
+ return true;
+ }
+ }
+
return false;
}
@@ -90,7 +90,7 @@ int TaskSO::runInner()
append(args, ld_option(toolchain, ctor::ld_opt::position_independent_code));
append(args, ld_option(toolchain, ctor::ld_opt::build_shared));
-
+ append(args, ld_option(toolchain, ctor::ld_opt::custom, "-Wl,-module"));
append(args, ld_option(toolchain, ctor::ld_opt::output, targetFile().string()));
for(const auto& task : getDependsTasks())
@@ -155,11 +155,6 @@ std::vector<std::string> TaskSO::depends() const
deps.push_back(objectFile.string());
}
- for(const auto& depFile : depFiles)
- {
- deps.push_back(depFile.string());
- }
-
return deps;
}
@@ -198,7 +193,7 @@ std::string TaskSO::flagsString() const
for(const auto& dep : config.depends)
{
- if(dep != config.depends[0])
+ if(&dep != &config.depends[0])
{
flagsStr += " ";
}
diff --git a/src/task_so.h b/src/task_so.h
index 60af225..c4283c1 100644
--- a/src/task_so.h
+++ b/src/task_so.h
@@ -14,7 +14,8 @@ class TaskSO
: public Task
{
public:
- TaskSO(const ctor::build_configuration& config,
+ TaskSO(ctor::target_type resolved_target_type,
+ const ctor::build_configuration& config,
const ctor::settings& settings,
const std::string& target,
const std::vector<std::string>& objects,
@@ -37,7 +38,6 @@ private:
std::string flagsString() const;
std::vector<std::filesystem::path> objectFiles;
- std::vector<std::filesystem::path> depFiles;
std::filesystem::path _targetFile;
std::filesystem::path flagsFile;
diff --git a/src/tasks.cc b/src/tasks.cc
index 2f9e47a..5e1d235 100644
--- a/src/tasks.cc
+++ b/src/tasks.cc
@@ -25,7 +25,7 @@
const std::deque<Target>& getTargets(const ctor::settings& settings,
bool resolve_externals)
{
- auto config_files = std::span(configFiles).subspan(0, numConfigFiles);
+ auto& config_files = getConfigFileList();
static bool initialised{false};
static std::deque<Target> targets;
@@ -82,30 +82,34 @@ std::vector<std::shared_ptr<Task>> taskFactory(const ctor::build_configuration&
std::filesystem::path targetFile(config.target);
- ctor::target_type target_type{config.type};
- if(target_type == ctor::target_type::automatic)
+ ctor::target_type resolved_target_type{config.type};
+ if(resolved_target_type == ctor::target_type::automatic)
{
- if(config.function != nullptr)
+ if(config.function_one_to_one || config.function_many_to_one)
{
- target_type = ctor::target_type::function;
+ resolved_target_type = ctor::target_type::function;
}
else
{
- target_type = target_type_from_extension(ctor::toolchain::any, targetFile);
+ resolved_target_type =
+ target_type_from_extension(ctor::toolchain::any, targetFile);
}
}
const auto& c = ctor::get_configuration();
std::vector<std::string> objects;
- if(target_type != ctor::target_type::function)
+ if(resolved_target_type != ctor::target_type::function)
{
for(const auto& source : config.sources)
{
if(source.toolchain == ctor::toolchain::any ||
- (config.system == ctor::output_system::build && source.toolchain == c.build_toolchain) ||
- (config.system == ctor::output_system::host && source.toolchain == c.host_toolchain))
+ (config.system == ctor::output_system::build &&
+ source.toolchain == c.build_toolchain) ||
+ (config.system == ctor::output_system::host &&
+ source.toolchain == c.host_toolchain))
{
- auto task = std::make_shared<TaskCC>(config, settings, sourceDir, source);
+ auto task =
+ std::make_shared<TaskCC>(ctor::target_type::object, config, settings, sourceDir, source);
tasks.push_back(task);
objects.push_back(task->targetFile().string());
}
@@ -114,16 +118,27 @@ std::vector<std::shared_ptr<Task>> taskFactory(const ctor::build_configuration&
#ifndef BOOTSTRAP
else
{
- for(const auto& file : config.sources)
+ if(config.function_many_to_one)
{
- auto task = std::make_shared<TaskFn>(config, settings, sourceDir, file);
+ auto task =
+ std::make_shared<TaskFn>(resolved_target_type, config, settings, sourceDir, "");
tasks.push_back(task);
objects.push_back(task->target());
}
+ else
+ {
+ for(const auto& source : config.sources)
+ {
+ auto task =
+ std::make_shared<TaskFn>(resolved_target_type, config, settings, sourceDir, source);
+ tasks.push_back(task);
+ objects.push_back(task->target());
+ }
+ }
}
#endif
- switch(target_type)
+ switch(resolved_target_type)
{
case ctor::target_type::automatic:
// The target_type cannot be Auto
@@ -137,25 +152,30 @@ std::vector<std::shared_ptr<Task>> taskFactory(const ctor::build_configuration&
case ctor::target_type::static_library:
case ctor::target_type::unit_test_library:
- tasks.push_back(std::make_shared<TaskAR>(config, settings, config.target,
- objects, sourceDir));
+ tasks.push_back(std::make_shared<TaskAR>(resolved_target_type, config, settings,
+ config.target, objects, sourceDir));
break;
#ifndef BOOTSTRAP
- case ctor::target_type::dynamic_library:
+ case ctor::target_type::shared_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.push_back(std::make_shared<TaskSO>(config, settings, config.target,
- objects, sourceDir));
+ tasks.push_back(std::make_shared<TaskSO>(resolved_target_type, config, settings,
+ config.target, objects, sourceDir));
+ break;
+
+ case ctor::target_type::module:
+ tasks.push_back(std::make_shared<TaskSO>(resolved_target_type, config, settings,
+ config.target, objects, sourceDir));
break;
case ctor::target_type::executable:
case ctor::target_type::unit_test:
- tasks.push_back(std::make_shared<TaskLD>(config, settings, config.target,
- objects, sourceDir, is_self));
+ tasks.push_back(std::make_shared<TaskLD>(resolved_target_type, config, settings,
+ config.target, objects, sourceDir, is_self));
break;
case ctor::target_type::object:
@@ -170,7 +190,8 @@ std::vector<std::shared_ptr<Task>> taskFactory(const ctor::build_configuration&
return tasks;
}
-std::shared_ptr<Task> getNextTask([[maybe_unused]]const std::vector<std::shared_ptr<Task>>& allTasks,
+std::shared_ptr<Task> getNextTask([[maybe_unused]]const ctor::settings& settings,
+ [[maybe_unused]]const std::vector<std::shared_ptr<Task>>& allTasks,
std::vector<std::shared_ptr<Task>>& dirtyTasks)
{
for(auto dirtyTask = dirtyTasks.begin();
@@ -179,7 +200,7 @@ std::shared_ptr<Task> getNextTask([[maybe_unused]]const std::vector<std::shared_
{
auto task = *dirtyTask;
//std::cout << "Examining target " << (*dirtyTask)->target() << "\n";
- if(task->ready())
+ if(task->ready() || settings.dry_run)
{
dirtyTasks.erase(dirtyTask);
return task;
diff --git a/src/tasks.h b/src/tasks.h
index 6573784..97fc84d 100644
--- a/src/tasks.h
+++ b/src/tasks.h
@@ -23,7 +23,8 @@ const std::deque<Target>& getTargets(const ctor::settings& settings,
//! 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::vector<std::shared_ptr<Task>>& allTasks,
+std::shared_ptr<Task> getNextTask(const ctor::settings& settings,
+ const std::vector<std::shared_ptr<Task>>& allTasks,
std::vector<std::shared_ptr<Task>>& dirtyTasks);
//! Get list of tasks filtered by name including each of their direct
diff --git a/src/tools.cc b/src/tools.cc
index dfabdff..e9c9b33 100644
--- a/src/tools.cc
+++ b/src/tools.cc
@@ -51,6 +51,7 @@ std::ostream& operator<<(std::ostream& stream, const ctor::cxx_opt& opt)
case ctor::cxx_opt::warn_shadow: stream << "ctor::cxx_opt::warn_shadow"; break;
case ctor::cxx_opt::warn_extra: stream << "ctor::cxx_opt::warn_extra"; break;
case ctor::cxx_opt::warnings_as_errors: stream << "ctor::cxx_opt::warnings_as_errors"; break;
+ case ctor::cxx_opt::exceptions: stream << "ctor::cxx_opt::exceptions"; 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;
@@ -112,7 +113,7 @@ std::ostream& operator<<(std::ostream& stream, const ctor::asm_opt& opt)
return stream;
}
-ctor::toolchain getToolChain(const std::string& compiler)
+ctor::toolchain getToolChain(std::string_view compiler)
{
std::filesystem::path cc(compiler);
auto cc_cmd = cc.stem().string();
@@ -209,7 +210,7 @@ std::string get_arch(ctor::output_system system)
return arch;
}
-ctor::arch get_arch(const std::string& str)
+ctor::arch get_arch(std::string_view str)
{
// gcc -v 2>&1 | grep Target
// Target: x86_64-apple-darwin19.6.0
@@ -244,24 +245,24 @@ ctor::arch get_arch(const std::string& str)
return ctor::arch::unknown;
}
-ctor::c_flag c_option(const std::string& flag)
+ctor::c_flag c_option(std::string_view flag)
{
if(flag.starts_with("-I"))
{
- std::string path = flag.substr(2);
+ std::string path(flag.substr(2));
path.erase(0, path.find_first_not_of(' '));
return { ctor::c_opt::include_path, path };
}
if(flag.starts_with("-std="))
{
- std::string std = flag.substr(5);
+ auto std = flag.substr(5);
return { ctor::c_opt::c_std, std };
}
if(flag.starts_with("-O"))
{
- std::string opt = flag.substr(2, 1);
+ auto opt = flag.substr(2, 1);
return { ctor::c_opt::optimization, opt };
}
@@ -297,7 +298,7 @@ ctor::c_flag c_option(const std::string& flag)
if(flag.starts_with("-D"))
{
- std::string def = flag.substr(2);
+ auto def = flag.substr(2);
auto pos = def.find('=');
if(pos != def.npos)
{
@@ -311,24 +312,24 @@ ctor::c_flag c_option(const std::string& flag)
return { ctor::c_opt::custom, flag };
}
-ctor::cxx_flag cxx_option(const std::string& flag)
+ctor::cxx_flag cxx_option(std::string_view flag)
{
if(flag.starts_with("-I"))
{
- std::string path = flag.substr(2);
+ std::string path(flag.substr(2));
path.erase(0, path.find_first_not_of(' '));
return { ctor::cxx_opt::include_path, path };
}
if(flag.starts_with("-std="))
{
- std::string std = flag.substr(5);
+ auto std = flag.substr(5);
return { ctor::cxx_opt::cpp_std, std };
}
if(flag.starts_with("-O"))
{
- std::string opt = flag.substr(2, 1);
+ auto opt = flag.substr(2, 1);
return { ctor::cxx_opt::optimization, opt };
}
@@ -357,6 +358,11 @@ ctor::cxx_flag cxx_option(const std::string& flag)
return { ctor::cxx_opt::warn_extra};
}
+ if(flag.starts_with("-fexceptions"))
+ {
+ return { ctor::cxx_opt::exceptions};
+ }
+
if(flag.starts_with("-g"))
{
return { ctor::cxx_opt::debug };
@@ -364,7 +370,7 @@ ctor::cxx_flag cxx_option(const std::string& flag)
if(flag.starts_with("-D"))
{
- std::string def = flag.substr(2);
+ auto def = flag.substr(2);
auto pos = def.find('=');
if(pos != def.npos)
{
@@ -379,11 +385,11 @@ ctor::cxx_flag cxx_option(const std::string& flag)
return { ctor::cxx_opt::custom, flag };
}
-ctor::ld_flag ld_option(const std::string& flag)
+ctor::ld_flag ld_option(std::string_view flag)
{
if(flag.starts_with("-L"))
{
- std::string path = flag.substr(2);
+ std::string path(flag.substr(2));
path.erase(0, path.find_first_not_of(' '));
return { ctor::ld_opt::library_path, path };
}
@@ -396,18 +402,18 @@ ctor::ld_flag ld_option(const std::string& flag)
return { ctor::ld_opt::custom, flag };
}
-ctor::ar_flag ar_option(const std::string& flag)
+ctor::ar_flag ar_option(std::string_view flag)
{
return { ctor::ar_opt::custom, flag };
}
-std::vector<std::string> cxx_option(ctor::cxx_opt opt, const std::string& arg,
- const std::string& arg2)
+std::vector<std::string> cxx_option(ctor::cxx_opt opt, std::string_view arg,
+ std::string_view arg2)
{
switch(opt)
{
case ctor::cxx_opt::output:
- return {"-o", arg};
+ return {"-o", std::string(arg)};
case ctor::cxx_opt::debug:
return {"-g"};
case ctor::cxx_opt::warn_all:
@@ -420,16 +426,18 @@ std::vector<std::string> cxx_option(ctor::cxx_opt opt, const std::string& arg,
return {"-Wextra"};
case ctor::cxx_opt::warnings_as_errors:
return {"-Werror"};
+ case ctor::cxx_opt::exceptions:
+ return {"-fexceptions"};
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};
+ return {"-I" + std::string(arg)};
case ctor::cxx_opt::cpp_std:
- return {"-std=" + arg};
+ return {"-std=" + std::string(arg)};
case ctor::cxx_opt::optimization:
- return {"-O" + arg};
+ return {"-O" + std::string(arg)};
case ctor::cxx_opt::position_independent_code:
return {"-fPIC"};
case ctor::cxx_opt::position_independent_executable:
@@ -437,9 +445,9 @@ std::vector<std::string> cxx_option(ctor::cxx_opt opt, const std::string& arg,
case ctor::cxx_opt::define:
if(!arg2.empty())
{
- return {"-D" + arg + "=" + arg2};
+ return {"-D" + std::string(arg) + "=" + std::string(arg2)};
}
- return {"-D" + arg};
+ return {"-D" + std::string(arg)};
case ctor::cxx_opt::custom:
return argsplit(arg);
}
@@ -448,13 +456,13 @@ std::vector<std::string> cxx_option(ctor::cxx_opt opt, const std::string& arg,
return {};
}
-std::vector<std::string> c_option(ctor::c_opt opt, const std::string& arg,
- const std::string& arg2)
+std::vector<std::string> c_option(ctor::c_opt opt, std::string_view arg,
+ std::string_view arg2)
{
switch(opt)
{
case ctor::c_opt::output:
- return {"-o", arg};
+ return {"-o", std::string(arg)};
case ctor::c_opt::debug:
return {"-g"};
case ctor::c_opt::warn_all:
@@ -472,11 +480,11 @@ std::vector<std::string> c_option(ctor::c_opt opt, const std::string& arg,
case ctor::c_opt::no_link:
return {"-c"};
case ctor::c_opt::include_path:
- return {"-I" + arg};
+ return {"-I" + std::string(arg)};
case ctor::c_opt::c_std:
- return {"-std=" + arg};
+ return {"-std=" + std::string(arg)};
case ctor::c_opt::optimization:
- return {"-O" + arg};
+ return {"-O" + std::string(arg)};
case ctor::c_opt::position_independent_code:
return {"-fPIC"};
case ctor::c_opt::position_independent_executable:
@@ -484,9 +492,9 @@ std::vector<std::string> c_option(ctor::c_opt opt, const std::string& arg,
case ctor::c_opt::define:
if(!arg2.empty())
{
- return {"-D" + arg + "=" + arg2};
+ return {"-D" + std::string(arg) + "=" + std::string(arg2)};
}
- return {"-D" + arg};
+ return {"-D" + std::string(arg)};
case ctor::c_opt::custom:
return argsplit(arg);
}
@@ -495,23 +503,23 @@ std::vector<std::string> c_option(ctor::c_opt opt, const std::string& arg,
return {};
}
-std::vector<std::string> ld_option(ctor::ld_opt opt, const std::string& arg,
- [[maybe_unused]]const std::string& arg2)
+std::vector<std::string> ld_option(ctor::ld_opt opt, std::string_view arg,
+ [[maybe_unused]]std::string_view arg2)
{
switch(opt)
{
case ctor::ld_opt::output:
- return {"-o", arg};
+ return {"-o", std::string(arg)};
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};
+ return {"-L" + std::string(arg)};
case ctor::ld_opt::link:
- return {"-l" + arg};
+ return {"-l" + std::string(arg)};
case ctor::ld_opt::cpp_std:
- return {"-std=" + arg};
+ return {"-std=" + std::string(arg)};
case ctor::ld_opt::build_shared:
return {"-shared"};
case ctor::ld_opt::threads:
@@ -528,8 +536,8 @@ std::vector<std::string> ld_option(ctor::ld_opt opt, const std::string& arg,
return {};
}
-std::vector<std::string> ar_option(ctor::ar_opt opt, const std::string& arg,
- [[maybe_unused]]const std::string& arg2)
+std::vector<std::string> ar_option(ctor::ar_opt opt, std::string_view arg,
+ [[maybe_unused]]std::string_view arg2)
{
switch(opt)
{
@@ -540,7 +548,7 @@ std::vector<std::string> ar_option(ctor::ar_opt opt, const std::string& arg,
case ctor::ar_opt::create:
return {"-c"};
case ctor::ar_opt::output:
- return {arg};
+ return {std::string(arg)};
case ctor::ar_opt::custom:
return argsplit(arg);
}
@@ -549,8 +557,8 @@ std::vector<std::string> ar_option(ctor::ar_opt opt, const std::string& arg,
return {};
}
-std::vector<std::string> asm_option(ctor::asm_opt opt, const std::string& arg,
- [[maybe_unused]]const std::string& arg2)
+std::vector<std::string> asm_option(ctor::asm_opt opt, std::string_view arg,
+ [[maybe_unused]]std::string_view arg2)
{
switch(opt)
{
@@ -578,7 +586,7 @@ std::string get_arch(ctor::output_system system)
return {};
}
-ctor::arch get_arch(ctor::output_system system, const std::string& str)
+ctor::arch get_arch(ctor::output_system system, std::string_view str)
{
auto toolchain = getToolChain(system);
switch(toolchain)
@@ -595,8 +603,8 @@ ctor::arch get_arch(ctor::output_system system, const std::string& str)
std::vector<std::string> c_option(ctor::toolchain toolchain,
ctor::c_opt opt,
- const std::string& arg,
- const std::string& arg2)
+ std::string_view arg,
+ std::string_view arg2)
{
switch(toolchain)
{
@@ -628,8 +636,8 @@ std::vector<std::string> c_option(ctor::toolchain toolchain,
std::vector<std::string> cxx_option(ctor::toolchain toolchain,
ctor::cxx_opt opt,
- const std::string& arg,
- const std::string& arg2)
+ std::string_view arg,
+ std::string_view arg2)
{
switch(toolchain)
{
@@ -661,8 +669,8 @@ std::vector<std::string> cxx_option(ctor::toolchain toolchain,
std::vector<std::string> ld_option(ctor::toolchain toolchain,
ctor::ld_opt opt,
- const std::string& arg,
- const std::string& arg2)
+ std::string_view arg,
+ std::string_view arg2)
{
switch(toolchain)
{
@@ -694,8 +702,8 @@ std::vector<std::string> ld_option(ctor::toolchain toolchain,
std::vector<std::string> ar_option(ctor::toolchain toolchain,
ctor::ar_opt opt,
- const std::string& arg,
- const std::string& arg2)
+ std::string_view arg,
+ std::string_view arg2)
{
switch(toolchain)
{
@@ -727,8 +735,8 @@ std::vector<std::string> ar_option(ctor::toolchain toolchain,
std::vector<std::string> asm_option(ctor::toolchain toolchain,
ctor::asm_opt opt,
- const std::string& arg,
- const std::string& arg2)
+ std::string_view arg,
+ std::string_view arg2)
{
switch(toolchain)
{
@@ -759,7 +767,7 @@ std::vector<std::string> asm_option(ctor::toolchain toolchain,
}
-ctor::c_flag c_option(const std::string& flag, ctor::toolchain toolchain)
+ctor::c_flag c_option(std::string_view flag, ctor::toolchain toolchain)
{
switch(toolchain)
{
@@ -774,7 +782,7 @@ ctor::c_flag c_option(const std::string& flag, ctor::toolchain toolchain)
return { ctor::c_opt::custom, flag };
}
-ctor::cxx_flag cxx_option(const std::string& flag, ctor::toolchain toolchain)
+ctor::cxx_flag cxx_option(std::string_view flag, ctor::toolchain toolchain)
{
switch(toolchain)
{
@@ -789,7 +797,7 @@ ctor::cxx_flag cxx_option(const std::string& flag, ctor::toolchain toolchain)
return { ctor::cxx_opt::custom, flag };
}
-ctor::ld_flag ld_option(const std::string& flag, ctor::toolchain toolchain)
+ctor::ld_flag ld_option(std::string_view flag, ctor::toolchain toolchain)
{
switch(toolchain)
{
@@ -804,7 +812,7 @@ ctor::ld_flag ld_option(const std::string& flag, ctor::toolchain toolchain)
return { ctor::ld_opt::custom, flag };
}
-ctor::ar_flag ar_option(const std::string& flag, ctor::toolchain toolchain)
+ctor::ar_flag ar_option(std::string_view flag, ctor::toolchain toolchain)
{
switch(toolchain)
{
@@ -819,7 +827,7 @@ ctor::ar_flag ar_option(const std::string& flag, ctor::toolchain toolchain)
return { ctor::ar_opt::custom, flag };
}
-ctor::asm_flag asm_option(const std::string& flag, ctor::toolchain toolchain)
+ctor::asm_flag asm_option(std::string_view flag, ctor::toolchain toolchain)
{
switch(toolchain)
{
@@ -896,7 +904,7 @@ std::vector<std::string> to_strings(ctor::toolchain toolchain,
}
namespace {
-ctor::toolchain guess_toolchain(const std::string& opt)
+ctor::toolchain guess_toolchain(std::string_view opt)
{
if(opt.empty())
{
@@ -916,32 +924,33 @@ ctor::toolchain guess_toolchain(const std::string& opt)
}
}
+
template<>
-ctor::flag<ctor::c_opt>::flag(const char* str)
+void ctor::flag<ctor::c_opt>::to_flag(std::string_view str)
{
*this = c_option(str, guess_toolchain(str));
}
template<>
-ctor::flag<ctor::cxx_opt>::flag(const char* str)
+void ctor::flag<ctor::cxx_opt>::to_flag(std::string_view str)
{
*this = cxx_option(str, guess_toolchain(str));
}
template<>
-ctor::flag<ctor::ld_opt>::flag(const char* str)
+void ctor::flag<ctor::ld_opt>::to_flag(std::string_view str)
{
*this = ld_option(str, guess_toolchain(str));
}
template<>
-ctor::flag<ctor::ar_opt>::flag(const char* str)
+void ctor::flag<ctor::ar_opt>::to_flag(std::string_view str)
{
*this = ar_option(str, guess_toolchain(str));
}
template<>
-ctor::flag<ctor::asm_opt>::flag(const char* str)
+void ctor::flag<ctor::asm_opt>::to_flag(std::string_view str)
{
*this = asm_option(str, guess_toolchain(str));
}
@@ -965,7 +974,14 @@ ctor::target_type target_type_from_extension(ctor::toolchain toolchain,
if(ext == ".so" ||
ext == ".dylib")
{
- return ctor::target_type::dynamic_library;
+ if(file.filename().string().substr(0, 3) != "lib")
+ {
+ return ctor::target_type::module;
+ }
+ else
+ {
+ return ctor::target_type::shared_library;
+ }
}
if(ext == ".o")
@@ -994,7 +1010,7 @@ ctor::target_type target_type_from_extension(ctor::toolchain toolchain,
if(ext == ".dll")
{
- return ctor::target_type::dynamic_library;
+ return ctor::target_type::shared_library;
}
if(ext == ".obj")
@@ -1078,7 +1094,8 @@ std::filesystem::path extension(ctor::toolchain toolchain,
break;
}
break;
- case ctor::target_type::dynamic_library:
+ case ctor::target_type::shared_library:
+ case ctor::target_type::module:
switch(arch)
{
case ctor::arch::unix:
diff --git a/src/tools.h b/src/tools.h
index 0e7fc15..b8df022 100644
--- a/src/tools.h
+++ b/src/tools.h
@@ -18,10 +18,10 @@ std::ostream& operator<<(std::ostream& stream, const ctor::ar_opt& opt);
std::ostream& operator<<(std::ostream& stream, const ctor::asm_opt& opt);
std::string get_arch(ctor::output_system system);
-ctor::arch get_arch(ctor::output_system system, const std::string& str);
+ctor::arch get_arch(ctor::output_system system, std::string_view str);
//! Get tool-chain type from compiler path string
-ctor::toolchain getToolChain(const std::string& compiler);
+ctor::toolchain getToolChain(std::string_view compiler);
//! Get tool-chain type from output system (via configuration)
ctor::toolchain getToolChain(ctor::output_system system);
@@ -32,63 +32,63 @@ ctor::toolchain getToolChain(ctor::output_system system);
//! tool-chain
std::vector<std::string> c_option(ctor::toolchain toolchain,
ctor::c_opt option,
- const std::string& arg = {},
- const std::string& arg2 = {});
+ std::string_view arg = {},
+ std::string_view arg2 = {});
//! 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 = {},
- const std::string& arg2 = {});
+ std::string_view arg = {},
+ std::string_view arg2 = {});
//! 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 = {},
- const std::string& arg2 = {});
+ std::string_view arg = {},
+ std::string_view arg2 = {});
//! 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 = {},
- const std::string& arg2 = {});
+ std::string_view arg = {},
+ std::string_view arg2 = {});
//! 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 = {},
- const std::string& arg2 = {});
+ std::string_view arg = {},
+ std::string_view arg2 = {});
//! 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);
+ctor::c_flag c_option(std::string_view 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);
+ctor::cxx_flag cxx_option(std::string_view 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);
+ctor::ld_flag ld_option(std::string_view 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);
+ctor::ar_flag ar_option(std::string_view 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);
+ctor::asm_flag asm_option(std::string_view flag, ctor::toolchain toolchain);
diff --git a/src/util.cc b/src/util.cc
index 6fc650a..7ca9c11 100644
--- a/src/util.cc
+++ b/src/util.cc
@@ -7,12 +7,17 @@
#include <fstream>
#include <algorithm>
#include <sstream>
+#include <cctype>
+#include <cstdlib>
-std::string to_lower(const std::string& str)
+std::string to_lower(std::string str)
{
- std::string out{str};
- std::transform(out.begin(), out.end(), out.begin(), ::tolower);
- return out;
+ std::transform(str.begin(), str.end(), str.begin(),
+ [](unsigned char c)
+ {
+ return static_cast<char>(std::tolower(c));
+ });
+ return str;
}
std::string readFile(const std::string& fileName)
@@ -20,13 +25,17 @@ 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();
+ auto size = ifs.tellg();
+ if(size < 0)
+ {
+ return {};
+ }
ifs.seekg(0, std::ios::beg);
- std::vector<char> bytes(static_cast<std::size_t>(fileSize));
- ifs.read(bytes.data(), fileSize);
+ std::string bytes(static_cast<std::size_t>(size), '\0');
+ ifs.read(bytes.data(), static_cast<std::streamsize>(bytes.size()));
- return {bytes.data(), static_cast<std::size_t>(fileSize)};
+ return bytes;
}
ctor::language languageFromExtension(const std::filesystem::path& file)
@@ -75,7 +84,7 @@ bool isClean(char c)
}
}
-std::string cleanUp(const std::string& path)
+std::string cleanUp(std::string_view path)
{
std::string cleaned;
for(const auto& c : path)
@@ -92,7 +101,7 @@ std::string cleanUp(const std::string& path)
return cleaned;
}
-std::string esc(const std::string& in)
+std::string esc(std::string_view in)
{
std::string out;
for(auto c : in)
@@ -109,8 +118,18 @@ std::string esc(const std::string& in)
return out;
}
-std::vector<std::string> get_paths(const std::string& path_env)
+std::vector<std::string> get_paths(std::string_view path_env_)
{
+ std::string path_env;
+ if(!path_env_.empty())
+ {
+ path_env = path_env_;
+ }
+ else
+ {
+ get_env("PATH", path_env);
+ }
+
std::vector<std::string> paths;
#ifdef _WIN32
@@ -186,7 +205,7 @@ std::string locate(const std::string& prog,
return {};
}
-std::vector<std::string> argsplit(const std::string& str)
+std::vector<std::string> argsplit(std::string_view str)
{
enum class state
{
@@ -277,3 +296,14 @@ std::vector<std::string> argsplit(const std::string& str)
}
return tokens;
}
+
+bool get_env(std::string_view name, std::string& value)
+{
+ auto var = getenv(name.data());
+ if(var)
+ {
+ value = var;
+ return true;
+ }
+ return false;
+}
diff --git a/src/util.h b/src/util.h
index 8b41014..7dbe2bb 100644
--- a/src/util.h
+++ b/src/util.h
@@ -9,11 +9,11 @@
#include <filesystem>
#include <cstdlib>
-std::string to_lower(const std::string& str);
+std::string to_lower(std::string str);
std::string readFile(const std::string& fileName);
ctor::language languageFromExtension(const std::filesystem::path& file);
-std::string cleanUp(const std::string& path);
+std::string cleanUp(std::string_view path);
template<typename T>
void append(T& a, const T& b)
@@ -21,13 +21,21 @@ void append(T& a, const T& b)
a.insert(a.end(), b.begin(), b.end());
}
-std::string esc(const std::string& in);
+std::string esc(std::string_view in);
-std::vector<std::string> get_paths(const std::string& path_env = std::getenv("PATH"));
+//! Get system paths (ie. env var PATH).
+//! If path_env is provided, this search string will be used, other the PATH
+//! env variable is used.
+//! \returns a vector of the individual toknized paths.
+std::vector<std::string> get_paths(std::string_view path_env = {});
std::string locate(const std::string& app,
const std::vector<std::string>& paths,
const std::string& arch = {});
//! Splits string into tokens adhering to quotations " and '
-std::vector<std::string> argsplit(const std::string& str);
+std::vector<std::string> argsplit(std::string_view str);
+
+//! Calls the system getenv and sets the string if the env name it exists.
+//! \returns true if the env name existed, false otherwise.
+bool get_env(std::string_view name, std::string& value);