Skip to content

Commit 544d1dd

Browse files
authored
feat: supporting defines in build recipes (#144)
1 parent f5865f9 commit 544d1dd

File tree

5 files changed

+128
-35
lines changed

5 files changed

+128
-35
lines changed

ecsact/cli/commands/build/build_recipe.cc

Lines changed: 64 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,11 @@ auto ecsact::build_recipe::system_libs() const -> std::span<const std::string> {
119119
return _system_libs;
120120
}
121121

122+
auto ecsact::build_recipe::defines() const
123+
-> std::unordered_map<std::string, std::string> {
124+
return _defines;
125+
}
126+
122127
static auto get_if_error( //
123128
const auto& result
124129
) -> std::optional<ecsact::build_recipe_parse_error> {
@@ -166,6 +171,19 @@ static auto parse_system_libs( //
166171
return system_libs.as<std::vector<std::string>>();
167172
}
168173

174+
static auto parse_defines( //
175+
YAML::Node defines
176+
)
177+
-> std::variant<
178+
std::unordered_map<std::string, std::string>,
179+
ecsact::build_recipe_parse_error> {
180+
if(!defines) {
181+
return {};
182+
}
183+
184+
return defines.as<std::unordered_map<std::string, std::string>>();
185+
}
186+
169187
static auto parse_sources( //
170188
fs::path recipe_path,
171189
YAML::Node sources
@@ -225,13 +243,15 @@ static auto parse_sources( //
225243
if(src["outdir"]) {
226244
outdir = src["outdir"].as<std::string>();
227245
}
228-
result.emplace_back(source_fetch{
229-
.url = fetch.as<std::string>(),
230-
.integrity = integrity,
231-
.strip_prefix = strip_prefix,
232-
.outdir = outdir,
233-
.paths = paths,
234-
});
246+
result.emplace_back(
247+
source_fetch{
248+
.url = fetch.as<std::string>(),
249+
.integrity = integrity,
250+
.strip_prefix = strip_prefix,
251+
.outdir = outdir,
252+
.paths = paths,
253+
}
254+
);
235255
} else if(path) {
236256
auto src_path = fs::path{path.as<std::string>()};
237257
auto outdir = std::optional<std::string>{};
@@ -248,17 +268,21 @@ static auto parse_sources( //
248268
src_path = src_path.lexically_normal();
249269
}
250270

251-
result.emplace_back(source_path{
252-
.path = src_path,
253-
.outdir = outdir,
254-
});
271+
result.emplace_back(
272+
source_path{
273+
.path = src_path,
274+
.outdir = outdir,
275+
}
276+
);
255277
}
256278
} else if(src.IsScalar()) {
257279
auto path = fs::path{src.as<std::string>()}.lexically_normal();
258-
result.emplace_back(source_path{
259-
.path = path,
260-
.outdir = ".",
261-
});
280+
result.emplace_back(
281+
source_path{
282+
.path = path,
283+
.outdir = ".",
284+
}
285+
);
262286
}
263287
}
264288

@@ -293,6 +317,11 @@ auto ecsact::build_recipe::build_recipe_from_yaml_node( //
293317
return *err;
294318
}
295319

320+
auto defines = parse_defines(doc["defines"]);
321+
if(auto err = get_if_error(defines)) {
322+
return *err;
323+
}
324+
296325
auto recipe = ecsact::build_recipe{};
297326
if(doc["name"]) {
298327
recipe._name = doc["name"].as<std::string>();
@@ -304,6 +333,7 @@ auto ecsact::build_recipe::build_recipe_from_yaml_node( //
304333
recipe._imports = get_value(imports);
305334
recipe._sources = get_value(sources);
306335
recipe._system_libs = get_value(system_libs);
336+
recipe._defines = get_value(defines);
307337

308338
if(recipe._exports.empty()) {
309339
return build_recipe_parse_error::missing_exports;
@@ -370,6 +400,13 @@ auto ecsact::build_recipe::to_yaml_string() const -> std::string {
370400
emitter << YAML::Key << "system_libs";
371401
emitter << YAML::Value << _system_libs;
372402

403+
emitter << YAML::Key << "defines";
404+
emitter << YAML::Value << YAML::BeginMap;
405+
for(auto&& [key, value] : _defines) {
406+
emitter << YAML::Key << key << YAML::Value << value;
407+
}
408+
emitter << YAML::EndMap;
409+
373410
emitter << YAML::Key << "sources";
374411
emitter << YAML::Value << _sources;
375412

@@ -423,6 +460,18 @@ auto ecsact::build_recipe::merge( //
423460
target._system_libs.end()
424461
);
425462

463+
merged_build_recipe._defines.reserve(
464+
merged_build_recipe._defines.size() + target._defines.size()
465+
);
466+
467+
for(auto&& [k, v] : base._defines) {
468+
merged_build_recipe._defines[k] = v;
469+
}
470+
471+
for(auto&& [k, v] : target._defines) {
472+
merged_build_recipe._defines[k] = v;
473+
}
474+
426475
merged_build_recipe._exports.reserve(
427476
merged_build_recipe._exports.size() + target._exports.size()
428477
);

ecsact/cli/commands/build/build_recipe.hh

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include <cstddef>
99
#include <optional>
1010
#include <filesystem>
11+
#include <unordered_map>
1112

1213
namespace YAML {
1314
class Node;
@@ -77,6 +78,7 @@ public:
7778
auto imports() const -> std::span<const std::string>;
7879
auto sources() const -> std::span<const source>;
7980
auto system_libs() const -> std::span<const std::string>;
81+
auto defines() const -> std::unordered_map<std::string, std::string>;
8082

8183
auto to_yaml_string() const -> std::string;
8284
auto to_yaml_bytes() const -> std::vector<std::byte>;
@@ -92,6 +94,8 @@ private:
9294
std::vector<source> _sources;
9395
std::vector<std::string> _system_libs;
9496

97+
std::unordered_map<std::string, std::string> _defines;
98+
9599
build_recipe();
96100
build_recipe(const build_recipe&);
97101

ecsact/cli/commands/build/recipe/cook.cc

Lines changed: 42 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -452,15 +452,16 @@ static auto generate_dylib_imports( //
452452
struct compile_options {
453453
fs::path work_dir;
454454

455-
ecsact::cli::cc_compiler compiler;
456-
std::vector<fs::path> inc_dirs;
457-
std::vector<std::string> system_libs;
458-
std::vector<fs::path> srcs;
459-
fs::path output_path;
460-
std::vector<std::string> imports;
461-
std::vector<std::string> exports;
462-
std::optional<fs::path> tracy_dir;
463-
bool debug;
455+
ecsact::cli::cc_compiler compiler;
456+
std::vector<fs::path> inc_dirs;
457+
std::vector<std::string> system_libs;
458+
std::unordered_map<std::string, std::string> defines;
459+
std::vector<fs::path> srcs;
460+
fs::path output_path;
461+
std::vector<std::string> imports;
462+
std::vector<std::string> exports;
463+
std::optional<fs::path> tracy_dir;
464+
bool debug;
464465
};
465466

466467
struct tracy_compile_options {
@@ -519,6 +520,14 @@ auto clang_gcc_compile(compile_options options) -> int {
519520

520521
compile_proc_args.push_back("-DECSACT_BUILD");
521522

523+
for(auto&& [name, value] : options.defines) {
524+
if(value.empty()) {
525+
compile_proc_args.push_back(std::format("-D{}", name));
526+
} else {
527+
compile_proc_args.push_back(std::format("-D{}={}", name, value));
528+
}
529+
}
530+
522531
for(auto def : generated_defines) {
523532
compile_proc_args.push_back(std::format("-D{}", def));
524533
}
@@ -756,6 +765,15 @@ auto cl_compile(compile_options options) -> int {
756765
cl_args.push_back("/D_WIN32_WINNT=0x0A00");
757766
cl_args.push_back("/diagnostics:column");
758767
cl_args.push_back("/DECSACT_BUILD");
768+
769+
for(auto&& [name, value] : options.defines) {
770+
if(value.empty()) {
771+
cl_args.push_back(std::format("/D{}", name));
772+
} else {
773+
cl_args.push_back(std::format("/D{}={}", name, value));
774+
}
775+
}
776+
759777
if(options.tracy_dir) {
760778
cl_args.push_back("/DTRACY_ENABLE");
761779
cl_args.push_back("/DTRACY_DELAYED_INIT");
@@ -836,8 +854,8 @@ auto cl_compile(compile_options options) -> int {
836854
src_compile_exit_code_futures.reserve(valid_srcs.size());
837855

838856
for(auto src : valid_srcs) {
839-
src_compile_exit_code_futures
840-
.emplace_back(std::async(std::launch::async, [&, src] {
857+
src_compile_exit_code_futures.emplace_back(
858+
std::async(std::launch::async, [&, src] {
841859
auto src_cl_args = cl_args;
842860
src_cl_args.push_back("/c");
843861
src_cl_args.push_back(std::format("@{}", main_params_file.string()));
@@ -850,17 +868,20 @@ auto cl_compile(compile_options options) -> int {
850868
src_cl_args.push_back("/std:c++20");
851869
}
852870

853-
src_cl_args.push_back(std::format(
854-
"/Fo{}\\", // typos:disable-line
855-
long_path_workaround(intermediate_dir).string()
856-
));
871+
src_cl_args.push_back(
872+
std::format(
873+
"/Fo{}\\", // typos:disable-line
874+
long_path_workaround(intermediate_dir).string()
875+
)
876+
);
857877

858878
return ecsact::cli::detail::spawn_and_report(
859879
options.compiler.compiler_path,
860880
src_cl_args,
861881
reporter
862882
);
863-
}));
883+
})
884+
);
864885
}
865886

866887
auto any_src_compile_failures = false;
@@ -890,9 +911,9 @@ auto cl_compile(compile_options options) -> int {
890911
cl_args.push_back(obj_f.string());
891912
}
892913

893-
auto obj_params_file =
894-
create_params_file(long_path_workaround(options.work_dir / "object.params")
895-
);
914+
auto obj_params_file = create_params_file(
915+
long_path_workaround(options.work_dir / "object.params")
916+
);
896917

897918
cl_args.push_back("/Fo:"); // typos:disable-line
898919
cl_args.push_back(
@@ -1078,6 +1099,7 @@ auto ecsact::cli::cook_recipe( //
10781099
.compiler = compiler,
10791100
.inc_dirs = inc_dirs,
10801101
.system_libs = as_vec(recipe.system_libs()),
1102+
.defines = recipe.defines(),
10811103
.srcs = source_files,
10821104
.output_path = output_path,
10831105
.imports = as_vec(recipe.imports()),
@@ -1091,6 +1113,7 @@ auto ecsact::cli::cook_recipe( //
10911113
.compiler = compiler,
10921114
.inc_dirs = inc_dirs,
10931115
.system_libs = as_vec(recipe.system_libs()),
1116+
.defines = recipe.defines(),
10941117
.srcs = source_files,
10951118
.output_path = output_path,
10961119
.imports = as_vec(recipe.imports()),

test/build_recipe/ecsact_build_test.cc

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,20 @@
55

66
// This define is _always_ defined when using the Ecsact CLI build command
77
#ifndef ECSACT_BUILD
8-
# error "This test should only have been built through 'ecsact build'"
8+
# error This test should only have been built through 'ecsact build'
9+
#endif
10+
11+
#ifndef EXAMPLE_DEFINE
12+
# error EXAMPLE_DEFINE should be been set in test-recipe.yml
13+
#endif
14+
15+
#ifdef EXAMPLE_DEFINE_WITH_VALUE
16+
static_assert(
17+
EXAMPLE_DEFINE_WITH_VALUE == 1,
18+
"EXAMPLE_DEFINE_WITH_VALUE should be been set to 1 in test-recipe.yml"
19+
);
20+
#else
21+
# error EXAMPLE_DEFINE_WITH_VALUE should be been set in test-recipe.yml
922
#endif
1023

1124
ecsact_registry_id ecsact_create_registry( //

test/build_recipe/test-recipe.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@ $schema: ../../schema/ecsact-build-recipe.schema.json
22

33
name: Example Recipe
44

5+
defines:
6+
EXAMPLE_DEFINE: ''
7+
EXAMPLE_DEFINE_WITH_VALUE: '1'
8+
59
sources:
610
- ecsact_build_test.cc
711
- codegen: ./test_codegen_plugin

0 commit comments

Comments
 (0)