diff options
Diffstat (limited to 'src/ctor.h')
| -rw-r--r-- | src/ctor.h | 177 |
1 files changed, 139 insertions, 38 deletions
@@ -10,6 +10,8 @@ #include <variant> #include <cstddef> #include <functional> +#include <string_view> +#include <cassert> namespace ctor { @@ -52,23 +54,6 @@ enum class arch unknown, //!< Target platform architecture has not yet detected or was not possible to detect }; -struct source -{ - source(const char* file) : file(file) {} - source(const std::string& file) : file(file) {} - source(const char* file, ctor::language lang) : file(file), language(lang) {} - source(const std::string& file, ctor::language lang) : file(file), language(lang) {} - - source(const char* file, const char* output) : file(file), output(output) {} - source(const std::string& file, const std::string& output) : file(file), output(output) {} - source(const char* file, ctor::language lang, const char* output) : file(file), language(lang), output(output) {} - source(const std::string& file, ctor::language lang, const std::string& output) : file(file), language(lang), output(output) {} - - std::string file; - ctor::language language{ctor::language::automatic}; - std::string output{}; -}; - enum class toolchain { any, @@ -77,12 +62,70 @@ enum class toolchain clang, }; +struct output_file +{ + std::string file; +}; + +enum class source_type +{ + regular, + generated, +}; + +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 { // gcc/clang output, // -o debug, // -g warn_all, // -Wall + warn_conversion, // -Wconversion + warn_shadow, // -Wshadow + warn_extra, // -Wextra warnings_as_errors, // -Werror generate_dep_tree, // -MMD no_link, // -c @@ -91,6 +134,7 @@ enum class cxx_opt optimization, // -O<arg> position_independent_code, // -fPIC position_independent_executable, // -fPIE + define, // -D<arg>[=<arg2>] custom, // entire option taken verbatim from <arg> }; @@ -100,6 +144,9 @@ enum class c_opt output, // -o debug, // -g warn_all, // -Wall + warn_conversion, // -Wconversion + warn_shadow, // -Wshadow + warn_extra, // -Wextra warnings_as_errors, // -Werror generate_dep_tree, // -MMD no_link, // -c @@ -108,6 +155,7 @@ enum class c_opt optimization, // -O<arg> position_independent_code, // -fPIC position_independent_executable, // -fPIE + define, // -D<arg>[=<arg2>] custom, // entire option taken verbatim from <arg> }; @@ -115,7 +163,6 @@ enum class ld_opt { // gcc/clang output, // -o - strip, // -s warn_all, // -Wall warnings_as_errors, // -Werror library_path, // -L<arg> @@ -149,18 +196,60 @@ template<typename T> class flag { public: - flag(const std::string& str); - flag(const char* str); - flag(T opt) : opt(opt) {} - flag(T opt, const std::string& arg) : opt(opt), arg(arg) {} - flag(T opt, const char* arg) : opt(opt), arg(arg) {} - flag(ctor::toolchain toolchain, T opt) : toolchain(toolchain), opt(opt) {} - flag(ctor::toolchain toolchain, T opt, const char* arg) : toolchain(toolchain), opt(opt), arg(arg) {} - flag(ctor::toolchain toolchain, T opt, const std::string& arg) : toolchain(toolchain), opt(opt), arg(arg) {} + 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; + T opt{}; std::string arg; + std::string arg2; + +private: + void to_flag(std::string_view str); }; using c_flag = ctor::flag<ctor::c_opt>; @@ -171,7 +260,7 @@ using asm_flag = ctor::flag<ctor::asm_opt>; using c_flags = std::vector<ctor::c_flag>; using cxx_flags = std::vector<ctor::cxx_flag>; -using ld_flags= std::vector<ctor::ld_flag>; +using ld_flags = std::vector<ctor::ld_flag>; using ar_flags = std::vector<ctor::ar_flag>; using asm_flags = std::vector<ctor::asm_flag>; @@ -189,13 +278,21 @@ 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 build_configuration { @@ -207,12 +304,14 @@ struct build_configuration std::vector<std::string> depends; // internal target dependencies ctor::flags flags; std::vector<std::string> externals; // externals used by this configuration - GeneratorCb function; + std::variant<std::monostate, + GeneratorOneToOne, + GeneratorManyToOne> function; }; using build_configurations = std::vector<build_configuration>; -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 @@ -231,7 +330,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) @@ -246,12 +345,12 @@ namespace cfg constexpr auto builddir = "builddir"; constexpr auto host_cc = "host-cc"; -constexpr auto host_cxx = "host-cpp"; +constexpr auto host_cxx = "host-cxx"; constexpr auto host_ar = "host-ar"; constexpr auto host_ld = "host-ld"; constexpr auto build_cc = "build-cc"; -constexpr auto build_cxx = "build-cpp"; +constexpr auto build_cxx = "build-cxx"; constexpr auto build_ar = "build-ar"; constexpr auto build_ld = "build-ld"; @@ -262,7 +361,7 @@ constexpr auto ctor_libdir = "ctor-libdir"; struct configuration { bool has(const std::string& key) const; - const std::string& get(const std::string& key, const std::string& default_value = {}) const; + std::string get(const std::string& key, const std::string& default_value = {}) const; ctor::toolchain host_toolchain{ctor::toolchain::none}; ctor::arch host_arch{ctor::arch::unknown}; @@ -271,6 +370,8 @@ struct configuration ctor::arch build_arch{ctor::arch::unknown}; std::vector<std::string> args; // vector of arguments used when last calling configure + + std::string getenv(const std::string& key) const; std::map<std::string, std::string> env; // env used when last calling configure std::map<std::string, std::string> tools; // tools |
