1
0
mirror of https://github.com/Kitware/CMake.git synced 2025-10-14 19:08:07 +08:00

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 <brad.king@kitware.com>
Fixes: #21295
This commit is contained in:
Johnny Jazeix
2020-10-13 23:48:12 +02:00
committed by Brad King
parent 90b39a5209
commit f7a5f28318
7 changed files with 31 additions and 7 deletions

View File

@@ -9,8 +9,10 @@
#include <cstring> #include <cstring>
#include <iostream> #include <iostream>
#include <string> #include <string>
#include <utility>
#include <vector> #include <vector>
#include <cm/memory>
#include <cmext/algorithm> #include <cmext/algorithm>
#include <cm3p/uv.h> #include <cm3p/uv.h>
@@ -107,13 +109,14 @@ const char* cmDocumentationOptions[][2] = {
#endif #endif
int do_command(int ac, char const* const* av) int do_command(int ac, char const* const* av,
std::unique_ptr<cmConsoleBuf> consoleBuf)
{ {
std::vector<std::string> args; std::vector<std::string> args;
args.reserve(ac - 1); args.reserve(ac - 1);
args.emplace_back(av[0]); args.emplace_back(av[0]);
cm::append(args, av + 2, av + ac); cm::append(args, av + 2, av + ac);
return cmcmd::ExecuteCMakeCommand(args); return cmcmd::ExecuteCMakeCommand(args, std::move(consoleBuf));
} }
cmMakefile* cmakemainGetMakefile(cmake* cm) cmMakefile* cmakemainGetMakefile(cmake* cm)
@@ -687,8 +690,8 @@ int main(int ac, char const* const* av)
cmSystemTools::EnsureStdPipes(); cmSystemTools::EnsureStdPipes();
// Replace streambuf so we can output Unicode to console // Replace streambuf so we can output Unicode to console
cmConsoleBuf consoleBuf; auto consoleBuf = cm::make_unique<cmConsoleBuf>();
consoleBuf.SetUTF8Pipes(); consoleBuf->SetUTF8Pipes();
cmsys::Encoding::CommandLineArguments args = cmsys::Encoding::CommandLineArguments args =
cmsys::Encoding::CommandLineArguments::Main(ac, av); cmsys::Encoding::CommandLineArguments::Main(ac, av);
@@ -708,7 +711,7 @@ int main(int ac, char const* const* av)
return do_open(ac, av); return do_open(ac, av);
} }
if (strcmp(av[1], "-E") == 0) { 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); int ret = do_cmake(ac, av);

View File

@@ -48,6 +48,12 @@
#include <sstream> #include <sstream>
#include <utility> #include <utility>
#ifdef _WIN32
# include <fcntl.h> // for _O_BINARY
# include <io.h> // for _setmode
# include <stdio.h> // for std{out,err} and fileno
#endif
#include <cm/string_view> #include <cm/string_view>
#include "cmsys/Directory.hxx" #include "cmsys/Directory.hxx"
@@ -178,6 +184,9 @@ static bool cmTarFilesFrom(std::string const& file,
static void cmCatFile(const std::string& fileToAppend) static void cmCatFile(const std::string& fileToAppend)
{ {
#ifdef _WIN32
_setmode(fileno(stdout), _O_BINARY);
#endif
cmsys::ifstream source(fileToAppend.c_str(), cmsys::ifstream source(fileToAppend.c_str(),
(std::ios::binary | std::ios::in)); (std::ios::binary | std::ios::in));
std::cout << source.rdbuf(); std::cout << source.rdbuf();
@@ -497,7 +506,8 @@ int cmcmd::HandleCoCompileCommands(std::vector<std::string> const& args)
return ret; return ret;
} }
int cmcmd::ExecuteCMakeCommand(std::vector<std::string> const& args) int cmcmd::ExecuteCMakeCommand(std::vector<std::string> const& args,
std::unique_ptr<cmConsoleBuf> consoleBuf)
{ {
// IF YOU ADD A NEW COMMAND, DOCUMENT IT ABOVE and in cmakemain.cxx // IF YOU ADD A NEW COMMAND, DOCUMENT IT ABOVE and in cmakemain.cxx
if (args.size() > 1) { if (args.size() > 1) {
@@ -951,6 +961,8 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string> const& args)
cmSystemTools::Error(arg + ": no such file or directory (ignoring)"); cmSystemTools::Error(arg + ": no such file or directory (ignoring)");
return_value = 1; return_value = 1;
} else { } else {
// Destroy console buffers to drop cout/cerr encoding transform.
consoleBuf.reset();
cmCatFile(arg); cmCatFile(arg);
} }
} }

View File

@@ -5,11 +5,14 @@
#include "cmConfigure.h" // IWYU pragma: keep #include "cmConfigure.h" // IWYU pragma: keep
#include <memory>
#include <string> #include <string>
#include <vector> #include <vector>
#include "cmCryptoHash.h" #include "cmCryptoHash.h"
class cmConsoleBuf;
class cmcmd class cmcmd
{ {
public: public:
@@ -17,7 +20,8 @@ public:
* Execute commands during the build process. Supports options such * Execute commands during the build process. Supports options such
* as echo, remove file etc. * as echo, remove file etc.
*/ */
static int ExecuteCMakeCommand(std::vector<std::string> const&); static int ExecuteCMakeCommand(std::vector<std::string> const&,
std::unique_ptr<cmConsoleBuf> consoleBuf);
protected: protected:
static int HandleCoCompileCommands(std::vector<std::string> const& args); static int HandleCoCompileCommands(std::vector<std::string> const& args);

View File

@@ -0,0 +1,2 @@
E_cat_binary_files/binary.obj -text
E_cat_good_binary_cat-stdout.txt -text -whitespace

View File

@@ -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") ${CMAKE_COMMAND} -E cat "${out}/first_file.txt" "${out}/second_file.txt" "${out}/unicode_file.txt")
unset(out) 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-command0 ${CMAKE_COMMAND} -E env)
run_cmake_command(E_env-no-command1 ${CMAKE_COMMAND} -E env TEST_ENV=1) 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) run_cmake_command(E_env-bad-arg1 ${CMAKE_COMMAND} -E env -bad-arg1)