From f7a5f283188c1e51b0fb549f0a78afaf1d570383 Mon Sep 17 00:00:00 2001 From: Johnny Jazeix Date: Tue, 13 Oct 2020 23:48:12 +0200 Subject: cmake: Fix '-E cat' command for binary files on Windows Reset `std::cout` to write in binary mode with no encoding conversions. Co-Author: Brad King Fixes: #21295 --- Source/cmakemain.cxx | 13 ++++++++----- Source/cmcmd.cxx | 14 +++++++++++++- Source/cmcmd.h | 6 +++++- Tests/RunCMake/CommandLine/.gitattributes | 2 ++ Tests/RunCMake/CommandLine/E_cat_binary_files/binary.obj | Bin 0 -> 124 bytes .../RunCMake/CommandLine/E_cat_good_binary_cat-stdout.txt | Bin 0 -> 248 bytes Tests/RunCMake/CommandLine/RunCMakeTest.cmake | 3 +++ 7 files changed, 31 insertions(+), 7 deletions(-) create mode 100644 Tests/RunCMake/CommandLine/.gitattributes create mode 100644 Tests/RunCMake/CommandLine/E_cat_binary_files/binary.obj create mode 100644 Tests/RunCMake/CommandLine/E_cat_good_binary_cat-stdout.txt diff --git a/Source/cmakemain.cxx b/Source/cmakemain.cxx index eb44329..7e589c0 100644 --- a/Source/cmakemain.cxx +++ b/Source/cmakemain.cxx @@ -9,8 +9,10 @@ #include #include #include +#include #include +#include #include #include @@ -107,13 +109,14 @@ const char* cmDocumentationOptions[][2] = { #endif -int do_command(int ac, char const* const* av) +int do_command(int ac, char const* const* av, + std::unique_ptr consoleBuf) { std::vector args; args.reserve(ac - 1); args.emplace_back(av[0]); cm::append(args, av + 2, av + ac); - return cmcmd::ExecuteCMakeCommand(args); + return cmcmd::ExecuteCMakeCommand(args, std::move(consoleBuf)); } cmMakefile* cmakemainGetMakefile(cmake* cm) @@ -687,8 +690,8 @@ int main(int ac, char const* const* av) cmSystemTools::EnsureStdPipes(); // Replace streambuf so we can output Unicode to console - cmConsoleBuf consoleBuf; - consoleBuf.SetUTF8Pipes(); + auto consoleBuf = cm::make_unique(); + consoleBuf->SetUTF8Pipes(); cmsys::Encoding::CommandLineArguments args = cmsys::Encoding::CommandLineArguments::Main(ac, av); @@ -708,7 +711,7 @@ int main(int ac, char const* const* av) return do_open(ac, av); } if (strcmp(av[1], "-E") == 0) { - return do_command(ac, av); + return do_command(ac, av, std::move(consoleBuf)); } } int ret = do_cmake(ac, av); diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx index 150fefd..a1fafcb 100644 --- a/Source/cmcmd.cxx +++ b/Source/cmcmd.cxx @@ -48,6 +48,12 @@ #include #include +#ifdef _WIN32 +# include // for _O_BINARY +# include // for _setmode +# include // for std{out,err} and fileno +#endif + #include #include "cmsys/Directory.hxx" @@ -178,6 +184,9 @@ static bool cmTarFilesFrom(std::string const& file, static void cmCatFile(const std::string& fileToAppend) { +#ifdef _WIN32 + _setmode(fileno(stdout), _O_BINARY); +#endif cmsys::ifstream source(fileToAppend.c_str(), (std::ios::binary | std::ios::in)); std::cout << source.rdbuf(); @@ -497,7 +506,8 @@ int cmcmd::HandleCoCompileCommands(std::vector const& args) return ret; } -int cmcmd::ExecuteCMakeCommand(std::vector const& args) +int cmcmd::ExecuteCMakeCommand(std::vector const& args, + std::unique_ptr consoleBuf) { // IF YOU ADD A NEW COMMAND, DOCUMENT IT ABOVE and in cmakemain.cxx if (args.size() > 1) { @@ -951,6 +961,8 @@ int cmcmd::ExecuteCMakeCommand(std::vector const& args) cmSystemTools::Error(arg + ": no such file or directory (ignoring)"); return_value = 1; } else { + // Destroy console buffers to drop cout/cerr encoding transform. + consoleBuf.reset(); cmCatFile(arg); } } diff --git a/Source/cmcmd.h b/Source/cmcmd.h index 5b6c813..ffadd5a 100644 --- a/Source/cmcmd.h +++ b/Source/cmcmd.h @@ -5,11 +5,14 @@ #include "cmConfigure.h" // IWYU pragma: keep +#include #include #include #include "cmCryptoHash.h" +class cmConsoleBuf; + class cmcmd { public: @@ -17,7 +20,8 @@ public: * Execute commands during the build process. Supports options such * as echo, remove file etc. */ - static int ExecuteCMakeCommand(std::vector const&); + static int ExecuteCMakeCommand(std::vector const&, + std::unique_ptr consoleBuf); protected: static int HandleCoCompileCommands(std::vector const& args); diff --git a/Tests/RunCMake/CommandLine/.gitattributes b/Tests/RunCMake/CommandLine/.gitattributes new file mode 100644 index 0000000..b0b0588 --- /dev/null +++ b/Tests/RunCMake/CommandLine/.gitattributes @@ -0,0 +1,2 @@ +E_cat_binary_files/binary.obj -text +E_cat_good_binary_cat-stdout.txt -text -whitespace diff --git a/Tests/RunCMake/CommandLine/E_cat_binary_files/binary.obj b/Tests/RunCMake/CommandLine/E_cat_binary_files/binary.obj new file mode 100644 index 0000000..73f1749 Binary files /dev/null and b/Tests/RunCMake/CommandLine/E_cat_binary_files/binary.obj differ diff --git a/Tests/RunCMake/CommandLine/E_cat_good_binary_cat-stdout.txt b/Tests/RunCMake/CommandLine/E_cat_good_binary_cat-stdout.txt new file mode 100644 index 0000000..0951d85 Binary files /dev/null and b/Tests/RunCMake/CommandLine/E_cat_good_binary_cat-stdout.txt differ diff --git a/Tests/RunCMake/CommandLine/RunCMakeTest.cmake b/Tests/RunCMake/CommandLine/RunCMakeTest.cmake index 973391d..abb9050 100644 --- a/Tests/RunCMake/CommandLine/RunCMakeTest.cmake +++ b/Tests/RunCMake/CommandLine/RunCMakeTest.cmake @@ -498,6 +498,9 @@ run_cmake_command(E_cat_good_cat ${CMAKE_COMMAND} -E cat "${out}/first_file.txt" "${out}/second_file.txt" "${out}/unicode_file.txt") unset(out) +run_cmake_command(E_cat_good_binary_cat + ${CMAKE_COMMAND} -E cat "${RunCMake_SOURCE_DIR}/E_cat_binary_files/binary.obj" "${RunCMake_SOURCE_DIR}/E_cat_binary_files/binary.obj") + run_cmake_command(E_env-no-command0 ${CMAKE_COMMAND} -E env) run_cmake_command(E_env-no-command1 ${CMAKE_COMMAND} -E env TEST_ENV=1) run_cmake_command(E_env-bad-arg1 ${CMAKE_COMMAND} -E env -bad-arg1) -- cgit v0.12