// -*- c++ -*- // Distributed under the BSD 2-Clause License. // See accompanying file LICENSE for details. #pragma once #include #include #include #include #include #include #include #include #include namespace ctor { enum class target_type { automatic, // Default - deduce from target name and sources extensions executable, static_library, dynamic_library, object, unit_test, unit_test_library, function, unknown, }; enum class language { automatic, // Default - deduce language from source extensions c, cpp, assembler, }; enum class output_system { host, // Output for the target system build, // Internal tool during cross-compilation }; enum class arch { unix, //!< Target platform architecture is unix-based (ie. linux, bsd, etc) apple, //!< Target platform architecture is macos windows, //!< Target platform architecture is windows unknown, //!< Target platform architecture has not yet detected or was not possible to detect }; enum class toolchain { any, none, gcc, clang, }; struct output_file { std::string file; }; struct source { template requires (( std::is_convertible_v || std::is_same_v || std::is_same_v || std::is_same_v ) && ...) constexpr source(Args && ... arg) { ([&] { if constexpr(std::is_convertible_v) { file = arg; } else if constexpr(std::is_same_v) { toolchain = arg; } else if constexpr(std::is_same_v) { language = arg; } else if constexpr(std::is_same_v) { output = arg.file; } }(), ...); } std::string file; ctor::toolchain toolchain{ctor::toolchain::any}; ctor::language language{ctor::language::automatic}; std::string output{}; }; 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 include_path, // -I cpp_std, // -std= optimization, // -O position_independent_code, // -fPIC position_independent_executable, // -fPIE define, // -D[=] custom, // entire option taken verbatim from }; enum class c_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 include_path, // -I c_std, // -std= optimization, // -O position_independent_code, // -fPIC position_independent_executable, // -fPIE define, // -D[=] custom, // entire option taken verbatim from }; enum class ld_opt { // gcc/clang output, // -o warn_all, // -Wall warnings_as_errors, // -Werror library_path, // -L link, // -l cpp_std, // -std= build_shared, // -shared threads, // -pthread position_independent_code, // -fPIC position_independent_executable, // -fPIE custom, // entire option taken verbatim from }; enum class ar_opt { // gcc/clang replace, // -r add_index, // -s create, // -c output, // custom, // entire option taken verbatim from }; enum class asm_opt { // gcc/clang custom, // entire option taken verbatim from }; template class flag { public: template requires (( std::is_convertible_v || std::is_same_v || std::is_same_v ) && ...) 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) { 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) { toolchain = _arg; } else if constexpr(std::is_same_v) { 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; using cxx_flag = ctor::flag; using ld_flag = ctor::flag; using ar_flag = ctor::flag; using asm_flag = ctor::flag; using c_flags = std::vector; using cxx_flags = std::vector; using ld_flags = std::vector; using ar_flags = std::vector; using asm_flags = std::vector; struct flags { ctor::c_flags cflags; // flags for c compiler ctor::cxx_flags cxxflags; // flags for c++ compiler ctor::ld_flags ldflags; // flags for linker ctor::ar_flags arflags; // flags for archiver ctor::asm_flags asmflags; // flags for asm translator }; struct settings { std::string builddir{"build"}; std::size_t parallel_processes{1}; int verbose{0}; // -1: completely silent, 0: normal, 1: verbose, ... bool dry_run{false}; }; struct build_configuration; using GeneratorCb = std::function; struct build_configuration { std::string name; // Name - used for referring in other configurations. ctor::target_type type{ctor::target_type::automatic}; ctor::output_system system{ctor::output_system::build}; std::string target; // Output target file for this configuration std::vector sources; // source list std::vector depends; // internal target dependencies ctor::flags flags; std::vector externals; // externals used by this configuration GeneratorCb function; }; using build_configurations = std::vector; int reg(std::function cb, const std::source_location location = std::source_location::current()); // This type will use flags verbatim struct external_manual { ctor::flags flags; }; struct external_configuration { std::string name; // Name for configuration ctor::output_system system{ctor::output_system::build}; std::variant external; }; using external_configurations = std::vector; int reg(std::function cb, const std::source_location location = std::source_location::current()); // Convenience macro - ugly but keeps things simple(r) #define CTOR_CONCAT(a, b) CTOR_CONCAT_INNER(a, b) #define CTOR_CONCAT_INNER(a, b) a ## b #define CTOR_UNIQUE_NAME(base) CTOR_CONCAT(base, __LINE__) #define REG(cb) namespace { int CTOR_UNIQUE_NAME(unique) = reg(cb); } // Predefined configuration keys namespace cfg { constexpr auto builddir = "builddir"; constexpr auto host_cc = "host-cc"; constexpr auto host_cxx = "host-cxx"; constexpr auto host_ar = "host-ar"; constexpr auto host_ld = "host-ld"; constexpr auto build_cc = "build-cc"; constexpr auto build_cxx = "build-cxx"; constexpr auto build_ar = "build-ar"; constexpr auto build_ld = "build-ld"; constexpr auto ctor_includedir = "ctor-includedir"; constexpr auto ctor_libdir = "ctor-libdir"; } struct configuration { bool has(const std::string& key) const; 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}; ctor::toolchain build_toolchain{ctor::toolchain::none}; ctor::arch build_arch{ctor::arch::unknown}; std::vector args; // vector of arguments used when last calling configure std::string getenv(const std::string& key) const; std::map env; // env used when last calling configure std::map tools; // tools std::map externals; }; const ctor::configuration& get_configuration(); } // ctor::