summaryrefslogtreecommitdiff
path: root/src/ctor.h
blob: 2fefac34fbabcb96ea8bc60ee7b823a10fef51b2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
// -*- 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
{
	Auto, // Default - deduce language from source extensions

	C,
	Cpp,
	Asm,
};

enum class OutputSystem
{
	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, Language lang) : file(file), language(lang) {}
	Source(const std::string& file, 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, Language lang, const char* output) : file(file), language(lang), output(output) {}
	Source(const std::string& file, Language lang, const std::string& output) : file(file), language(lang), output(output) {}

	std::string file;
	Language language{Language::Auto};
	std::string output{};
};

struct Flags
{
	std::vector<std::string> cxxflags; // flags for c++ compiler
	std::vector<std::string> cflags; // flags for c compiler
	std::vector<std::string> ldflags; // flags for linker
	std::vector<std::string> 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 BuildConfiguration;
using GeneratorCb = std::function<int(const std::string& input,
                                      const std::string& output,
                                      const BuildConfiguration& config,
                                      const Settings& settings)>;

struct BuildConfiguration
{
	std::string name; // Name - used for referring in other configurations.
	ctor::target_type type{ctor::target_type::automatic};
	OutputSystem system{OutputSystem::Host};
	std::string target; // Output target file for this configuration
	std::vector<Source> sources; // source list
	std::vector<std::string> depends; // internal target dependencies
	Flags flags;
	std::vector<std::string> externals; // externals used by this configuration
	GeneratorCb function;
};

using BuildConfigurations = std::vector<BuildConfiguration>;

int reg(BuildConfigurations (*cb)(const Settings&),
        const std::source_location location = std::source_location::current());

// This type will use flags verbatim
struct ExternalManual
{
	Flags flags;
};


struct ExternalConfiguration
{
	std::string name; // Name for configuration
	OutputSystem system{OutputSystem::Host};
	std::variant<ExternalManual> external;
};

using ExternalConfigurations = std::vector<ExternalConfiguration>;

int reg(ExternalConfigurations (*cb)(const 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
{
	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, Flags> externals;
};

const Configuration& configuration();
bool hasConfiguration(const std::string& key);
const std::string& getConfiguration(const std::string& key,
                                    const std::string& defaultValue = {});

} // namespace ctor::