From cc2ed456ae45b099acd25d748e29053a401ae8fc Mon Sep 17 00:00:00 2001 From: Ezekiel Warren Date: Fri, 13 Sep 2024 16:35:31 -0700 Subject: [PATCH 1/5] feat: compiling each c/c++ file individually --- ecsact/cli/commands/build/recipe/cook.cc | 191 +++++++++++++++++------ 1 file changed, 144 insertions(+), 47 deletions(-) diff --git a/ecsact/cli/commands/build/recipe/cook.cc b/ecsact/cli/commands/build/recipe/cook.cc index 8af7a46..0819419 100644 --- a/ecsact/cli/commands/build/recipe/cook.cc +++ b/ecsact/cli/commands/build/recipe/cook.cc @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #undef fopen @@ -332,12 +333,6 @@ static auto handle_source( // ec.message() ); return 1; - } else { - ecsact::cli::report_info( - "Copied source {} to {}", - src_path.generic_string(), - rel_outdir.generic_string() - ); } } @@ -583,6 +578,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,10 +616,25 @@ auto cl_compile(compile_options options) -> int { ); }; + auto intermediate_dir = + fs::path{options.work_dir / "intermediate"}.lexically_normal(); + auto ec = std::error_code{}; + fs::create_directories(intermediate_dir); + auto cl_args = std::vector{}; + auto create_params_file = [&cl_args](fs::path params_file_path) -> fs::path { + auto params_file = std::ofstream{params_file_path}; + for(auto arg : cl_args) { + params_file << std::format("\"{}\"\n", arg); + } + + cl_args.clear(); + return params_file_path; + }; + cl_args.push_back("/nologo"); - cl_args.push_back("/std:c++20"); + cl_args.push_back("/D_WIN32_WINNT=0x0A00"); cl_args.push_back("/diagnostics:column"); cl_args.push_back("/DECSACT_BUILD"); @@ -616,10 +654,6 @@ auto cl_compile(compile_options options) -> int { cl_args.push_back("/O2"); cl_args.push_back("/GL"); cl_args.push_back("/MP"); - cl_args.push_back("/Fo:"); // typos:disable-line - cl_args.push_back( - std::format("{}\\", fs::path{options.work_dir}.lexically_normal().string()) - ); auto generated_defines = ecsact::cli::cc_defines_gen(options.imports, options.exports); @@ -633,6 +667,24 @@ auto cl_compile(compile_options options) -> int { cl_args.push_back(std::format("/D{}", def)); } + 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 : options.system_libs) { + cl_args.push_back(std::format("/DEFAULTLIB:{}", sys_lib)); + } + + auto main_params_file = + create_params_file(long_path_workaround(options.work_dir / "main.params")); + + auto valid_srcs = std::vector{}; + valid_srcs.reserve(options.srcs.size()); + for(auto src : options.srcs) { if(src.extension().string().starts_with(".h")) { continue; @@ -642,21 +694,82 @@ auto cl_compile(compile_options options) -> int { continue; } - cl_args.push_back(abs_from_wd(src).string()); + if(src.extension().empty()) { + continue; + } + + if(src.string().empty()) { + continue; + } + + valid_srcs.emplace_back(src); } - for(auto inc_dir : options.compiler.std_inc_paths) { - cl_args.push_back(std::format("/I{}", inc_dir.string())); + auto src_compile_exit_code_futures = std::vector>{}; + src_compile_exit_code_futures.reserve(valid_srcs.size()); + + for(auto src : valid_srcs) { + src_compile_exit_code_futures + .emplace_back(std::async(std::launch::async, [&, src] { + auto src_cl_args = cl_args; + src_cl_args.push_back("/c"); + src_cl_args.push_back(std::format("@{}", main_params_file.string())); + src_cl_args.push_back(abs_from_wd(src).string()); + // src_cl_args.push_back(src.string()); + + if(src.extension() == ".c") { + src_cl_args.push_back("/std:c17"); + } else { + src_cl_args.push_back("/std:c++20"); + } + + src_cl_args.push_back(std::format( + "/Fo{}\\", + long_path_workaround(intermediate_dir).string() + )); + + return ecsact::cli::detail::spawn_and_report( + options.compiler.compiler_path, + src_cl_args, + reporter + ); + })); } - for(auto inc_dir : options.inc_dirs) { - cl_args.push_back(std::format("/I{}", inc_dir.string())); + auto any_src_compile_failures = false; + auto src_compile_exit_codes = std::vector>{}; + src_compile_exit_codes.reserve(src_compile_exit_code_futures.size()); + + for(auto i = 0; src_compile_exit_code_futures.size() > i; ++i) { + auto& fut = src_compile_exit_code_futures.at(i); + auto compile_exit_code = fut.get(); + + if(compile_exit_code != 0) { + any_src_compile_failures = true; + ecsact::cli::report_error( + "Failed to compile {}. Compiler {} exited with code {}", + valid_srcs.at(i).generic_string(), + to_string(options.compiler.compiler_type), + compile_exit_code + ); + } } - for(auto sys_lib : options.system_libs) { - cl_args.push_back(std::format("/DEFAULTLIB:{}", sys_lib)); + if(any_src_compile_failures) { + return 1; } + cl_args.push_back("@" + main_params_file.string()); + + for(fs::path obj_f : fs::recursive_directory_iterator(intermediate_dir)) { + cl_args.push_back(obj_f.string()); + } + + cl_args.push_back("/Fo:"); // typos:disable-line + cl_args.push_back( + std::format("{}\\", fs::path{options.work_dir}.lexically_normal().string()) + ); + cl_args.push_back("/link"); if(options.debug) { cl_args.push_back("/DEBUG"); @@ -671,34 +784,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, @@ -842,7 +927,19 @@ auto ecsact::cli::cook_recipe( // auto rel_hdr_path = hdr.substr("ecsact_runtime/"sv.size()); fs::create_directories((inc_dir / rel_hdr_path).parent_path(), ec); - fs::copy_file(full_hdr_path, inc_dir / rel_hdr_path, ec); + if(fs::exists(inc_dir / rel_hdr_path)) { + ecsact::cli::report_warning( + "Overwriting ecsact runtime header {} with runfiles header", + rel_hdr_path + ); + } + + fs::copy_file( + full_hdr_path, + inc_dir / rel_hdr_path, + fs::copy_options::overwrite_existing, + ec + ); if(ec) { ecsact::cli::report_error( "Failed to copy ecsact runtime header from runfiles. {} -> {}\n{}", From 503e299a8694c73cf7e1ffefd1b49d08814dda75 Mon Sep 17 00:00:00 2001 From: Ezekiel Warren Date: Thu, 19 Sep 2024 14:18:31 -0700 Subject: [PATCH 2/5] feat: debug flag --- ecsact/cli/commands/build/recipe/cook.cc | 31 ++++++++++++------------ 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/ecsact/cli/commands/build/recipe/cook.cc b/ecsact/cli/commands/build/recipe/cook.cc index 0819419..b4ecfe9 100644 --- a/ecsact/cli/commands/build/recipe/cook.cc +++ b/ecsact/cli/commands/build/recipe/cook.cc @@ -638,22 +638,21 @@ auto cl_compile(compile_options options) -> int { 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"); + if(options.debug) { + cl_args.push_back("/DEBUG:FULL"); + cl_args.push_back("/MDd"); + cl_args.push_back("/Z7"); + cl_args.push_back("/EHsc"); + cl_args.push_back("/bigobj"); + } else { + // 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 generated_defines = ecsact::cli::cc_defines_gen(options.imports, options.exports); From 8155a3f6553f40fac3ea83800dbcb032b877800c Mon Sep 17 00:00:00 2001 From: Ezekiel Warren Date: Sat, 21 Sep 2024 13:00:53 -0700 Subject: [PATCH 3/5] fix: relative recipe paths correctly resolved --- ecsact/cli/commands/build/build_recipe.cc | 2 +- ecsact/cli/commands/build/recipe/cook.cc | 26 +++++++++++++++---- .../recipe-bundle/build_recipe_bundle.cc | 7 ++++- 3 files changed, 28 insertions(+), 7 deletions(-) diff --git a/ecsact/cli/commands/build/build_recipe.cc b/ecsact/cli/commands/build/build_recipe.cc index 63e9512..cbf1115 100644 --- a/ecsact/cli/commands/build/build_recipe.cc +++ b/ecsact/cli/commands/build/build_recipe.cc @@ -473,7 +473,7 @@ auto ecsact::build_recipe::merge( // if(std::holds_alternative(src)) { source_path src_path = std::get(src); if(!src_path.path.is_absolute()) { - src_path.path = fs::relative( + src_path.path = fs::proximate( target.base_directory() / src_path.path, base.base_directory() ); diff --git a/ecsact/cli/commands/build/recipe/cook.cc b/ecsact/cli/commands/build/recipe/cook.cc index b4ecfe9..b9a7cfc 100644 --- a/ecsact/cli/commands/build/recipe/cook.cc +++ b/ecsact/cli/commands/build/recipe/cook.cc @@ -310,30 +310,46 @@ static auto handle_source( // } for(auto path : paths) { - if(!fs::exists(src_path)) { + if(!fs::exists(path)) { ecsact::cli::report_error( "Source file {} does not exist", - src_path.generic_string() + path.generic_string() ); return 1; } + if(fs::is_directory(path)) { + ecsact::cli::report_warning( + "Ignoring directory source {} ", + path.generic_string() + ); + continue; + } auto rel_outdir = outdir; - if(auto stripped = path_strip_prefix(src_path, before_glob)) { + if(auto stripped = path_strip_prefix(path, before_glob)) { rel_outdir = outdir / *stripped; } + rel_outdir = rel_outdir.lexically_normal(); + fs::create_directories(rel_outdir, ec); - fs::copy(src_path, rel_outdir, ec); + fs::copy(path, rel_outdir, ec); if(ec) { ecsact::cli::report_error( "Failed to copy source {} to {}: {}", - src_path.generic_string(), + path.generic_string(), rel_outdir.generic_string(), ec.message() ); return 1; } + + ecsact::cli::report_info( + "Copied {} to {}", + path.string(), + rel_outdir.string(), + ec.message() + ); } return 0; diff --git a/ecsact/cli/commands/recipe-bundle/build_recipe_bundle.cc b/ecsact/cli/commands/recipe-bundle/build_recipe_bundle.cc index 79a698c..060f737 100644 --- a/ecsact/cli/commands/recipe-bundle/build_recipe_bundle.cc +++ b/ecsact/cli/commands/recipe-bundle/build_recipe_bundle.cc @@ -296,13 +296,18 @@ auto ecsact::build_recipe_bundle::create( // return src; }, [&](build_recipe::source_path src) -> source_visitor_result_t { + auto src_path = src.path; + if(!src_path.is_absolute()) { + src_path = recipe.base_directory() / src.path; + } auto src_path_basename = src.path.filename(); auto archive_rel_path = (fs::path{"files"} / src.outdir.value_or(".") / src_path_basename) .lexically_normal(); - auto file_buffer = read_file(src.path); + auto file_buffer = read_file(src_path); if(!file_buffer) { + __debugbreak(); return std::logic_error{"read file fail"}; } From 6ca7e098d102901b0568a1ac57ac4fd2df63dec0 Mon Sep 17 00:00:00 2001 From: Ezekiel Warren Date: Mon, 23 Sep 2024 12:16:07 -0700 Subject: [PATCH 4/5] fix: ignore typo --- ecsact/cli/commands/build/recipe/cook.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ecsact/cli/commands/build/recipe/cook.cc b/ecsact/cli/commands/build/recipe/cook.cc index b9a7cfc..da79222 100644 --- a/ecsact/cli/commands/build/recipe/cook.cc +++ b/ecsact/cli/commands/build/recipe/cook.cc @@ -739,7 +739,7 @@ auto cl_compile(compile_options options) -> int { } src_cl_args.push_back(std::format( - "/Fo{}\\", + "/Fo{}\\", // typos:disable-line long_path_workaround(intermediate_dir).string() )); From 6a61b0faf30a234c772561dc0415ac5e4da8b223 Mon Sep 17 00:00:00 2001 From: Ezekiel Warren Date: Mon, 23 Sep 2024 12:46:05 -0700 Subject: [PATCH 5/5] fix: remove debugbreak --- ecsact/cli/commands/recipe-bundle/build_recipe_bundle.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/ecsact/cli/commands/recipe-bundle/build_recipe_bundle.cc b/ecsact/cli/commands/recipe-bundle/build_recipe_bundle.cc index 060f737..e986491 100644 --- a/ecsact/cli/commands/recipe-bundle/build_recipe_bundle.cc +++ b/ecsact/cli/commands/recipe-bundle/build_recipe_bundle.cc @@ -307,7 +307,6 @@ auto ecsact::build_recipe_bundle::create( // auto file_buffer = read_file(src_path); if(!file_buffer) { - __debugbreak(); return std::logic_error{"read file fail"}; }