summaryrefslogtreecommitdiff
path: root/src/ctor.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/ctor.h')
-rw-r--r--src/ctor.h268
1 files changed, 268 insertions, 0 deletions
diff --git a/src/ctor.h b/src/ctor.h
new file mode 100644
index 0000000..b8b3ae6
--- /dev/null
+++ b/src/ctor.h
@@ -0,0 +1,268 @@
+// -*- c++ -*-
+// Distributed under the BSD 2-Clause License.
+// See accompanying file LICENSE for details.
+#pragma once
+
+#include <source_location>
+#include <string>
+#include <vector>
+#include <map>
+#include <variant>
+#include <cstddef>
+#include <functional>
+
+namespace ctor {
+
+enum class target_type
+{
+ automatic, // Default - deduce from target name and sources extensions
+
+ executable,
+ static_library,
+ dynamic_library,
+ object,
+ unit_test,
+ unit_test_library,
+ function,
+};
+
+enum class language
+{
+ automatic, // Default - deduce language from source extensions
+
+ c,
+ cpp,
+ assembler,
+};
+
+enum class output_system
+{
+ host, // Output for the target system
+ build, // Internal tool during cross-compilation
+};
+
+struct source
+{
+ source(const char* file) : file(file) {}
+ source(const std::string& file) : file(file) {}
+ source(const char* file, ctor::language lang) : file(file), language(lang) {}
+ source(const std::string& file, ctor::language lang) : file(file), language(lang) {}
+
+ source(const char* file, const char* output) : file(file), output(output) {}
+ source(const std::string& file, const std::string& output) : file(file), output(output) {}
+ source(const char* file, ctor::language lang, const char* output) : file(file), language(lang), output(output) {}
+ source(const std::string& file, ctor::language lang, const std::string& output) : file(file), language(lang), output(output) {}
+
+ std::string file;
+ ctor::language language{ctor::language::automatic};
+ std::string output{};
+};
+
+enum class toolchain
+{
+ any,
+ none,
+ gcc,
+ clang,
+};
+
+enum class cxx_opt
+{
+ // gcc/clang
+ output, // -o
+ debug, // -g
+ warn_all, // -Wall
+ warnings_as_errors, // -Werror
+ generate_dep_tree, // -MMD
+ no_link, // -c
+ include_path, // -I<arg>
+ cpp_std, // -std=<arg>
+ optimization, // -O<arg>
+ position_independent_code, // -fPIC
+ position_independent_executable, // -fPIE
+ custom, // entire option taken verbatim from <arg>
+};
+
+enum class c_opt
+{
+ // gcc/clang
+ output, // -o
+ debug, // -g
+ warn_all, // -Wall
+ warnings_as_errors, // -Werror
+ generate_dep_tree, // -MMD
+ no_link, // -c
+ include_path, // -I<arg>
+ c_std, // -std=<arg>
+ optimization, // -O<arg>
+ position_independent_code, // -fPIC
+ position_independent_executable, // -fPIE
+ custom, // entire option taken verbatim from <arg>
+};
+
+enum class ld_opt
+{
+ // gcc/clang
+ output, // -o
+ strip, // -s
+ warn_all, // -Wall
+ warnings_as_errors, // -Werror
+ library_path, // -L<arg>
+ link, // -l<arg>
+ cpp_std, // -std=<arg>
+ build_shared, // -shared
+ threads, // -pthread
+ position_independent_code, // -fPIC
+ position_independent_executable, // -fPIE
+ custom, // entire option taken verbatim from <arg>
+};
+
+enum class ar_opt
+{
+ // gcc/clang
+ replace, // -r
+ add_index, // -s
+ create, // -c
+ output, // <arg>
+
+ custom, // entire option taken verbatim from <arg>
+};
+
+enum class asm_opt
+{
+ // gcc/clang
+ custom, // entire option taken verbatim from <arg>
+};
+
+template<typename T>
+class flag
+{
+public:
+ flag(const std::string& str);
+ flag(const char* str);
+ flag(T opt) : opt(opt) {}
+ flag(T opt, const std::string& arg) : opt(opt), arg(arg) {}
+ flag(T opt, const char* arg) : opt(opt), arg(arg) {}
+ flag(ctor::toolchain toolchain, T opt) : toolchain(toolchain), opt(opt) {}
+ flag(ctor::toolchain toolchain, T opt, const char* arg) : toolchain(toolchain), opt(opt), arg(arg) {}
+ flag(ctor::toolchain toolchain, T opt, const std::string& arg) : toolchain(toolchain), opt(opt), arg(arg) {}
+
+ ctor::toolchain toolchain{ctor::toolchain::any};
+ T opt;
+ std::string arg;
+};
+
+using c_flag = ctor::flag<ctor::c_opt>;
+using cxx_flag = ctor::flag<ctor::cxx_opt>;
+using ld_flag = ctor::flag<ctor::ld_opt>;
+using ar_flag = ctor::flag<ctor::ar_opt>;
+using asm_flag = ctor::flag<ctor::asm_opt>;
+
+using c_flags = std::vector<ctor::c_flag>;
+using cxx_flags = std::vector<ctor::cxx_flag>;
+using ld_flags= std::vector<ctor::ld_flag>;
+using ar_flags = std::vector<ctor::ar_flag>;
+using asm_flags = std::vector<ctor::asm_flag>;
+
+struct flags
+{
+ ctor::c_flags cflags; // flags for c compiler
+ ctor::cxx_flags cxxflags; // flags for c++ compiler
+ ctor::ld_flags ldflags; // flags for linker
+ ctor::ar_flags arflags; // flags for archiver
+ ctor::asm_flags asmflags; // flags for asm translator
+};
+
+struct settings
+{
+ std::string builddir{"build"};
+ std::size_t parallel_processes{1};
+ int verbose{0}; // -1: completely silent, 0: normal, 1: verbose, ...
+};
+
+struct build_configuration;
+using GeneratorCb = std::function<int(const std::string& input,
+ const std::string& output,
+ const build_configuration& config,
+ const ctor::settings& settings)>;
+
+struct build_configuration
+{
+ std::string name; // Name - used for referring in other configurations.
+ ctor::target_type type{ctor::target_type::automatic};
+ ctor::output_system system{ctor::output_system::host};
+ std::string target; // Output target file for this configuration
+ std::vector<ctor::source> sources; // source list
+ std::vector<std::string> depends; // internal target dependencies
+ ctor::flags flags;
+ std::vector<std::string> externals; // externals used by this configuration
+ GeneratorCb function;
+};
+
+using build_configurations = std::vector<build_configuration>;
+
+int reg(ctor::build_configurations (*cb)(const ctor::settings&),
+ const std::source_location location = std::source_location::current());
+
+// This type will use flags verbatim
+struct external_manual
+{
+ ctor::flags flags;
+};
+
+
+struct external_configuration
+{
+ std::string name; // Name for configuration
+ ctor::output_system system{ctor::output_system::host};
+ std::variant<ctor::external_manual> external;
+};
+
+using external_configurations = std::vector<ctor::external_configuration>;
+
+int reg(ctor::external_configurations (*cb)(const ctor::settings&),
+ const std::source_location location = std::source_location::current());
+
+// Convenience macro - ugly but keeps things simple(r)
+#define CONCAT(a, b) CONCAT_INNER(a, b)
+#define CONCAT_INNER(a, b) a ## b
+#define UNIQUE_NAME(base) CONCAT(base, __LINE__)
+#define REG(cb) namespace { int UNIQUE_NAME(unique) = reg(cb); }
+
+// Predefined configuration keys
+namespace cfg
+{
+constexpr auto builddir = "builddir";
+
+constexpr auto host_cc = "host-cc";
+constexpr auto host_cxx = "host-cpp";
+constexpr auto host_ar = "host-ar";
+constexpr auto host_ld = "host-ld";
+
+constexpr auto build_cc = "build-cc";
+constexpr auto build_cxx = "build-cpp";
+constexpr auto build_ar = "build-ar";
+constexpr auto build_ld = "build-ld";
+
+constexpr auto ctor_includedir = "ctor-includedir";
+constexpr auto ctor_libdir = "ctor-libdir";
+}
+
+struct configuration
+{
+ bool has(const std::string& key) const;
+ const std::string& get(const std::string& key, const std::string& default_value = {}) const;
+
+ ctor::toolchain host_toolchain{ctor::toolchain::none};
+ ctor::toolchain build_toolchain{ctor::toolchain::none};
+
+ std::vector<std::string> args; // vector of arguments used when last calling configure
+ std::map<std::string, std::string> env; // env used when last calling configure
+
+ std::map<std::string, std::string> tools; // tools
+ std::map<std::string, ctor::flags> externals;
+};
+
+const ctor::configuration& get_configuration();
+
+} // ctor::