From cae769467a94977eeef2f2085b72504c630d3f16 Mon Sep 17 00:00:00 2001 From: Ezekiel Warren Date: Fri, 13 Sep 2024 14:15:44 -0700 Subject: [PATCH] feat: allow specifying libs --- ecsact/cli/commands/build/build_recipe.cc | 41 +++++ ecsact/cli/commands/build/build_recipe.hh | 9 ++ ecsact/cli/commands/build/recipe/cook.cc | 176 ++++++++++++++-------- 3 files changed, 167 insertions(+), 59 deletions(-) diff --git a/ecsact/cli/commands/build/build_recipe.cc b/ecsact/cli/commands/build/build_recipe.cc index 63e9512..2236977 100644 --- a/ecsact/cli/commands/build/build_recipe.cc +++ b/ecsact/cli/commands/build/build_recipe.cc @@ -265,6 +265,41 @@ static auto parse_sources( // return result; } +static auto parse_libs( // + fs::path recipe_path, + YAML::Node libs +) + -> std::variant< + std::vector, + ecsact::build_recipe_parse_error> { + auto result = std::vector{}; + + for(auto lib_doc : libs) { + if(!lib_doc.IsMap()) { + return ecsact::build_recipe_parse_error::invalid_lib; + } + + auto sources = parse_sources(recipe_path, lib_doc["sources"]); + if(auto err = get_if_error(sources)) { + return *err; + } + + auto system_libs = parse_system_libs(lib_doc["system_libs"]); + if(auto err = get_if_error(system_libs)) { + return *err; + } + + auto lib = ecsact::build_recipe::lib{}; + lib.name = lib_doc["name"].as(); + lib.sources = get_value(sources); + lib.system_libs = get_value(system_libs); + + result.emplace_back(std::move(lib)); + } + + return result; +} + auto ecsact::build_recipe::build_recipe_from_yaml_node( // YAML::Node doc, fs::path p @@ -293,6 +328,11 @@ auto ecsact::build_recipe::build_recipe_from_yaml_node( // return *err; } + auto libs = parse_libs(p, doc["libs"]); + if(auto err = get_if_error(libs)) { + return *err; + } + auto recipe = ecsact::build_recipe{}; if(doc["name"]) { recipe._name = doc["name"].as(); @@ -304,6 +344,7 @@ auto ecsact::build_recipe::build_recipe_from_yaml_node( // recipe._imports = get_value(imports); recipe._sources = get_value(sources); recipe._system_libs = get_value(system_libs); + recipe._libs = get_value(libs); if(recipe._exports.empty()) { return build_recipe_parse_error::missing_exports; diff --git a/ecsact/cli/commands/build/build_recipe.hh b/ecsact/cli/commands/build/build_recipe.hh index 70c9872..0cec1d4 100644 --- a/ecsact/cli/commands/build/build_recipe.hh +++ b/ecsact/cli/commands/build/build_recipe.hh @@ -23,6 +23,7 @@ enum class build_recipe_parse_error { unknown_import_method, unknown_export_method, conflicting_import_export_method_modules, + invalid_lib, }; enum class build_recipe_merge_error { @@ -68,6 +69,12 @@ public: using source = std::variant; + struct lib { + std::string name; + std::vector sources; + std::vector system_libs; + }; + build_recipe(build_recipe&&); ~build_recipe(); @@ -76,6 +83,7 @@ public: auto exports() const -> std::span; auto imports() const -> std::span; auto sources() const -> std::span; + auto libs() const -> std::span; auto system_libs() const -> std::span; auto to_yaml_string() const -> std::string; @@ -90,6 +98,7 @@ private: std::vector _exports; std::vector _imports; std::vector _sources; + std::vector _libs; std::vector _system_libs; build_recipe(); diff --git a/ecsact/cli/commands/build/recipe/cook.cc b/ecsact/cli/commands/build/recipe/cook.cc index 8af7a46..b32f57b 100644 --- a/ecsact/cli/commands/build/recipe/cook.cc +++ b/ecsact/cli/commands/build/recipe/cook.cc @@ -420,17 +420,23 @@ static auto generate_dylib_imports( // output << "}\n\n"; } +struct compile_lib_options { + std::vector system_libs; + std::vector srcs; +}; + struct compile_options { fs::path work_dir; - ecsact::cli::cc_compiler compiler; - std::vector inc_dirs; - std::vector system_libs; - std::vector srcs; - fs::path output_path; - std::vector imports; - std::vector exports; - bool debug; + ecsact::cli::cc_compiler compiler; + std::vector inc_dirs; + std::vector system_libs; + std::vector srcs; + fs::path output_path; + std::vector imports; + std::vector exports; + std::vector libs; + bool debug; }; auto clang_gcc_compile(compile_options options) -> int { @@ -583,6 +589,34 @@ auto clang_gcc_compile(compile_options options) -> int { } auto cl_compile(compile_options options) -> int { + struct : ecsact::cli::detail::spawn_reporter { + auto on_std_out(std::string_view line) -> std::optional { + if(line.find(": warning") != std::string::npos) { + return ecsact::cli::warning_message{ + .content = std::string{line}, + }; + } else if(line.find(": error") != std::string::npos) { + return ecsact::cli::error_message{ + .content = std::string{line}, + }; + } else if(line.find(": fatal error ") != std::string::npos) { + return ecsact::cli::error_message{ + .content = std::string{line}, + }; + } else if(line.find(": Command line error ") != std::string::npos) { + return ecsact::cli::error_message{ + .content = std::string{line}, + }; + } + + return {}; + } + + auto on_std_err(std::string_view line) -> std::optional { + return {}; + } + } reporter; + auto abs_from_wd = [&options](fs::path rel_path) { assert(!rel_path.empty()); if(rel_path.is_absolute()) { @@ -593,29 +627,81 @@ auto cl_compile(compile_options options) -> int { ); }; - auto cl_args = std::vector{}; - - cl_args.push_back("/nologo"); - cl_args.push_back("/std:c++20"); - cl_args.push_back("/diagnostics:column"); - cl_args.push_back("/DECSACT_BUILD"); - - // TODO(zaucy): Add debug mode - // if(options.debug) { - // compile_proc_args.push_back("/DEBUG:FULL"); - // compile_proc_args.push_back("/MDd"); - // compile_proc_args.push_back("/Z7"); - // compile_proc_args.push_back("/EHsc"); - // compile_proc_args.push_back("/bigobj"); - // } - - // cl_args.push_back("/we4530"); // treat exceptions as errors - cl_args.push_back("/wd4530"); // ignore use of exceptions warning - cl_args.push_back("/MD"); - cl_args.push_back("/DNDEBUG"); - cl_args.push_back("/O2"); - cl_args.push_back("/GL"); - cl_args.push_back("/MP"); + auto prepare_default_cl_args = [&] { + auto cl_args = std::vector{}; + + cl_args.push_back("/nologo"); + cl_args.push_back("/std:c++20"); + cl_args.push_back("/diagnostics:column"); + cl_args.push_back("/DECSACT_BUILD"); + + // TODO(zaucy): Add debug mode + // if(options.debug) { + // compile_proc_args.push_back("/DEBUG:FULL"); + // compile_proc_args.push_back("/MDd"); + // compile_proc_args.push_back("/Z7"); + // compile_proc_args.push_back("/EHsc"); + // compile_proc_args.push_back("/bigobj"); + // } + + // cl_args.push_back("/we4530"); // treat exceptions as errors + cl_args.push_back("/wd4530"); // ignore use of exceptions warning + cl_args.push_back("/MD"); + cl_args.push_back("/DNDEBUG"); + cl_args.push_back("/O2"); + cl_args.push_back("/GL"); + cl_args.push_back("/MP"); + return cl_args; + }; + + auto lib_objs = std::vector(); + + for(auto lib : options.libs) { + auto cl_args = prepare_default_cl_args(); + + cl_args.push_back("/LIB"); + + for(auto src : lib.srcs) { + if(src.extension().string().starts_with(".h")) { + continue; + } + + if(src.extension().string() == ".ipp") { + continue; + } + + cl_args.push_back(abs_from_wd(src).string()); + } + + for(auto inc_dir : options.compiler.std_inc_paths) { + cl_args.push_back(std::format("/I{}", inc_dir.string())); + } + + for(auto inc_dir : options.inc_dirs) { + cl_args.push_back(std::format("/I{}", inc_dir.string())); + } + + for(auto sys_lib : lib.system_libs) { + cl_args.push_back(std::format("/DEFAULTLIB:{}", sys_lib)); + } + + auto lib_compile_exit_code = ecsact::cli::detail::spawn_and_report( + options.compiler.compiler_path, + cl_args, + reporter + ); + + if(lib_compile_exit_code != 0) { + ecsact::cli::report_error( + "Failed to compile recipe lib. Compiler {} exited with code {}", + to_string(options.compiler.compiler_type), + lib_compile_exit_code + ); + return 1; + } + } + + auto cl_args = prepare_default_cl_args(); cl_args.push_back("/Fo:"); // typos:disable-line cl_args.push_back( std::format("{}\\", fs::path{options.work_dir}.lexically_normal().string()) @@ -671,34 +757,6 @@ auto cl_compile(compile_options options) -> int { cl_args.push_back(std::format("/OUT:{}", options.output_path.string())); - struct : ecsact::cli::detail::spawn_reporter { - auto on_std_out(std::string_view line) -> std::optional { - if(line.find(": warning") != std::string::npos) { - return ecsact::cli::warning_message{ - .content = std::string{line}, - }; - } else if(line.find(": error") != std::string::npos) { - return ecsact::cli::error_message{ - .content = std::string{line}, - }; - } else if(line.find(": fatal error ") != std::string::npos) { - return ecsact::cli::error_message{ - .content = std::string{line}, - }; - } else if(line.find(": Command line error ") != std::string::npos) { - return ecsact::cli::error_message{ - .content = std::string{line}, - }; - } - - return {}; - } - - auto on_std_err(std::string_view line) -> std::optional { - return {}; - } - } reporter; - auto compile_exit_code = ecsact::cli::detail::spawn_and_report( options.compiler.compiler_path, cl_args,