// -*- c++ -*- // Distributed under the BSD 2-Clause License. // See accompanying file LICENSE for details. #pragma once #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 source { 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_) {} source(ctor::toolchain toolchain_, std::string_view file_, std::string_view output_) : file(file_), toolchain(toolchain_), output(output_) {} source(ctor::toolchain toolchain_, std::string_view file_, ctor::language lang_, std::string_view output_) : file(file_), toolchain(toolchain_), language(lang_), output(output_) {} 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 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 custom, // entire option taken verbatim from }; enum class c_opt { // gcc/clang output, // -o debug, // -g warn_all, // -Wall warnings_as_errors, // -Werror generate_dep_tree, // -MMD no_link, // -c include_path, // -I c_std, // -std= optimization, // -O position_independent_code, // -fPIC position_independent_executable, // -fPIE custom, // entire option taken verbatim from }; enum class ld_opt { // gcc/clang output, // -o strip, // -s 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: flag(std::string_view str); flag(const char* str); flag(T opt_) : opt(opt_) {} flag(T opt_, std::string_view 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_, std::string_view arg_) : toolchain(toolchain_), opt(opt_), arg(arg_) {} ctor::toolchain toolchain{ctor::toolchain::any}; T opt{}; std::string arg; }; 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, ... }; 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(ctor::build_configurations (*cb)(const ctor::settings&), const std::source_location location = std::source_location::current()); // This type will use flags verbatim struct external_manual { ctor::flags flags; }; struct external_configuration { std::string name; // Name for configuration ctor::output_system system{ctor::output_system::build}; std::variant external; }; using external_configurations = std::vector; int reg(ctor::external_configurations (*cb)(const ctor::settings&), const std::source_location location = std::source_location::current()); // Convenience macro - ugly but keeps things simple(r) #define 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-cpp"; constexpr auto host_ar = "host-ar"; constexpr auto host_ld = "host-ld"; constexpr auto build_cc = "build-cc"; constexpr auto build_cxx = "build-cpp"; constexpr auto build_ar = "build-ar"; constexpr auto build_ld = "build-ld"; constexpr auto ctor_includedir = "ctor-includedir"; constexpr auto ctor_libdir = "ctor-libdir"; } struct configuration { bool has(const std::string& key) const; const std::string& get(const std::string& key, const std::string& default_value = {}) const; ctor::toolchain host_toolchain{ctor::toolchain::none}; ctor::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::map env; // env used when last calling configure std::map tools; // tools std::map externals; }; const ctor::configuration& get_configuration(); } // ctor::