diff --git a/ecsact/cli/commands/build/recipe/BUILD.bazel b/ecsact/cli/commands/build/recipe/BUILD.bazel index d6a491b..66127da 100644 --- a/ecsact/cli/commands/build/recipe/BUILD.bazel +++ b/ecsact/cli/commands/build/recipe/BUILD.bazel @@ -48,6 +48,7 @@ cc_library( "//ecsact/cli/detail:download", "//ecsact/cli/detail:glob", "//ecsact/cli/detail:archive", + "//ecsact/cli/detail:long_path_workaround", "//ecsact/cli/commands/build:build_recipe", "//ecsact/cli/commands/build:cc_compiler_config", "//ecsact/cli/commands/build:cc_defines_gen", diff --git a/ecsact/cli/commands/build/recipe/cook.cc b/ecsact/cli/commands/build/recipe/cook.cc index 104e26c..8af7a46 100644 --- a/ecsact/cli/commands/build/recipe/cook.cc +++ b/ecsact/cli/commands/build/recipe/cook.cc @@ -24,6 +24,7 @@ #include "ecsact/cli/detail/download.hh" #include "ecsact/cli/detail/glob.hh" #include "ecsact/cli/detail/archive.hh" +#include "ecsact/cli/detail/long_path_workaround.hh" #ifndef ECSACT_CLI_USE_SDK_VERSION # include "tools/cpp/runfiles/runfiles.h" #endif @@ -34,6 +35,7 @@ using ecsact::cli::report_warning; using ecsact::cli::detail::download_file; using ecsact::cli::detail::expand_path_globs; using ecsact::cli::detail::integrity; +using ecsact::cli::detail::long_path_workaround; using ecsact::cli::detail::path_before_glob; using ecsact::cli::detail::path_matches_glob; using ecsact::cli::detail::path_strip_prefix; @@ -286,6 +288,8 @@ static auto handle_source( // src_path = (base_directory / src_path).lexically_normal(); } + src_path = long_path_workaround(src_path); + auto outdir = src.outdir // ? options.work_dir / *src.outdir : options.work_dir; @@ -490,6 +494,10 @@ auto clang_gcc_compile(compile_options options) -> int { continue; } + if(src.extension().string() == ".ipp") { + continue; + } + compile_proc_args.push_back(fs::relative(src, options.work_dir).string()); } @@ -630,6 +638,10 @@ auto cl_compile(compile_options options) -> int { continue; } + if(src.extension().string() == ".ipp") { + continue; + } + cl_args.push_back(abs_from_wd(src).string()); } diff --git a/ecsact/cli/commands/recipe-bundle/BUILD.bazel b/ecsact/cli/commands/recipe-bundle/BUILD.bazel index 6b4b21d..d81dcba 100644 --- a/ecsact/cli/commands/recipe-bundle/BUILD.bazel +++ b/ecsact/cli/commands/recipe-bundle/BUILD.bazel @@ -16,6 +16,7 @@ cc_library( "//ecsact/cli/commands/codegen", "//ecsact/cli/commands/build:build_recipe", "//ecsact/cli/detail:download", + "//ecsact/cli/detail:long_path_workaround", "//ecsact/cli:report", ], ) diff --git a/ecsact/cli/commands/recipe-bundle/build_recipe_bundle.cc b/ecsact/cli/commands/recipe-bundle/build_recipe_bundle.cc index 493849e..79a698c 100644 --- a/ecsact/cli/commands/recipe-bundle/build_recipe_bundle.cc +++ b/ecsact/cli/commands/recipe-bundle/build_recipe_bundle.cc @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -18,11 +19,13 @@ #include #include #include "xxhash.h" - #include "ecsact/cli/report.hh" #include "ecsact/cli/detail/download.hh" +#include "ecsact/cli/detail/long_path_workaround.hh" #include "ecsact/cli/commands/codegen/codegen_util.hh" +using ecsact::cli::detail::long_path_workaround; + using namespace std::string_literals; using namespace std::string_view_literals; namespace fs = std::filesystem; @@ -87,7 +90,7 @@ static auto is_valid_bundle_entry_path(std::string_view path) -> bool { static auto read_file(fs::path path) -> std::optional> { auto ec = std::error_code{}; - auto file_size = fs::file_size(path, ec); + auto file_size = fs::file_size(long_path_workaround(path), ec); if(ec) { ecsact::cli::report_error( "failed to read file size {}: {}", @@ -96,7 +99,7 @@ static auto read_file(fs::path path) -> std::optional> { ); return {}; } - auto file = std::ifstream{path, std::ios_base::binary}; + auto file = std::ifstream{long_path_workaround(path), std::ios_base::binary}; if(!file) { ecsact::cli::report_error( "failed to open file file for reading {}", @@ -117,15 +120,46 @@ static auto read_file(fs::path path) -> std::optional> { return file_buffer; } -static auto write_file(fs::path path, std::span data) -> void { - if(path.has_parent_path()) { +static auto write_file(fs::path path, std::span data) -> bool { + if(path.has_parent_path() && !fs::exists(path.parent_path())) { auto ec = std::error_code{}; - fs::create_directories(path.parent_path(), ec); + fs::create_directories(long_path_workaround(path.parent_path()), ec); + if(ec) { + ecsact::cli::report_error( + "failed to create directory {}: {}", + path.generic_string(), + ec.message() + ); + return false; + } + } + + auto file = std::ofstream{ + long_path_workaround(path), + std::ios::binary | std::ios::trunc + }; + if(!file) { + ecsact::cli::report_error( + "failed to open file {}: {}", + path.generic_string(), + std::strerror(errno) + ); + return false; } - auto file = std::ofstream(path, std::ios_base::binary | std::ios_base::trunc); - assert(file); file.write(reinterpret_cast(data.data()), data.size()); + + if(!file) { + ecsact::cli::report_error( + "failed to write file {}: {}", + path.generic_string(), + std::strerror(errno) + ); + return false; + } + + file.flush(); + return true; } ecsact::build_recipe_bundle::build_recipe_bundle() = default; @@ -399,7 +433,11 @@ auto ecsact::build_recipe_bundle::extract( // return std::logic_error{std::format("Failed to read {}", path)}; } - write_file(dir / path, data); + if(!write_file(dir / path, data)) { + return std::logic_error{ + std::format("Failed to extract {}", (dir / path).generic_string()) + }; + } } archive_entry_free(entry); diff --git a/ecsact/cli/detail/BUILD.bazel b/ecsact/cli/detail/BUILD.bazel index 1c248b2..6bdd390 100644 --- a/ecsact/cli/detail/BUILD.bazel +++ b/ecsact/cli/detail/BUILD.bazel @@ -74,3 +74,10 @@ cc_library( "@boost.process", ], ) + +cc_library( + name = "long_path_workaround", + copts = copts, + hdrs = ["long_path_workaround.hh"], + srcs = ["long_path_workaround.cc"], +) diff --git a/ecsact/cli/detail/long_path_workaround.cc b/ecsact/cli/detail/long_path_workaround.cc new file mode 100644 index 0000000..b241b34 --- /dev/null +++ b/ecsact/cli/detail/long_path_workaround.cc @@ -0,0 +1,17 @@ +#include "ecsact/cli/detail/long_path_workaround.hh" + +auto ecsact::cli::detail::long_path_workaround( // + std::filesystem::path p +) -> std::filesystem::path { +#if _WIN32 + auto win_path_str = "\\\\?\\" + std::filesystem::absolute(p).string(); + for(auto& c : win_path_str) { + if(c == '/') { + c = '\\'; + } + } + return win_path_str; +#else + return p; +#endif +} diff --git a/ecsact/cli/detail/long_path_workaround.hh b/ecsact/cli/detail/long_path_workaround.hh new file mode 100644 index 0000000..4cd67ef --- /dev/null +++ b/ecsact/cli/detail/long_path_workaround.hh @@ -0,0 +1,13 @@ +#pragma once + +#include + +namespace ecsact::cli::detail { + +/** + * The Ecsact CLI isn't built with long path awareness on Windows. This utility + * function returns an absolute //?/ prefixed path on Windows and on other + * platforms does nothing. + */ +auto long_path_workaround(std::filesystem::path p) -> std::filesystem::path; +} // namespace ecsact::cli::detail