1
0
mirror of https://github.com/Kitware/CMake.git synced 2025-10-20 12:53:55 +08:00

execute_process: Add ENCODING option for Windows child process output

Different applications can use different output encodings.
This commit is contained in:
Dāvis Mosāns
2016-11-23 14:11:40 +02:00
committed by Brad King
parent 076aef8e45
commit 2ed473b3b8
16 changed files with 125 additions and 2 deletions

View File

@@ -18,7 +18,8 @@ Execute one or more child processes.
[OUTPUT_QUIET] [OUTPUT_QUIET]
[ERROR_QUIET] [ERROR_QUIET]
[OUTPUT_STRIP_TRAILING_WHITESPACE] [OUTPUT_STRIP_TRAILING_WHITESPACE]
[ERROR_STRIP_TRAILING_WHITESPACE]) [ERROR_STRIP_TRAILING_WHITESPACE]
[ENCODING <name>])
Runs the given sequence of one or more commands in parallel with the standard Runs the given sequence of one or more commands in parallel with the standard
output of each process piped to the standard input of the next. output of each process piped to the standard input of the next.
@@ -66,6 +67,14 @@ Options:
``OUTPUT_QUIET``, ``ERROR_QUIET`` ``OUTPUT_QUIET``, ``ERROR_QUIET``
The standard output or standard error results will be quietly ignored. The standard output or standard error results will be quietly ignored.
``ENCODING <name>``
On Windows, the encoding that is used to decode output from the process.
Ignored on other platforms.
Valid encoding names are: ``AUTO`` (the default), ``NONE``, ``UTF8``,
``ANSI`` and ``OEM``.
``AUTO`` encoding means current active console's codepage will be used
or if that isn't available then ``ANSI`` codepage will be used.
If more than one ``OUTPUT_*`` or ``ERROR_*`` option is given for the If more than one ``OUTPUT_*`` or ``ERROR_*`` option is given for the
same pipe the precedence is not specified. same pipe the precedence is not specified.
If no ``OUTPUT_*`` or ``ERROR_*`` options are given the output will If no ``OUTPUT_*`` or ``ERROR_*`` options are given the output will

View File

@@ -0,0 +1,5 @@
execute_process-encoding
------------------------
* The :command:`execute_process` command gained an ``ENCODING`` option to
specify on Windows which encoding is used for output from child process.

View File

@@ -47,6 +47,7 @@ bool cmExecuteProcessCommand::InitialPass(std::vector<std::string> const& args,
std::string error_variable; std::string error_variable;
std::string result_variable; std::string result_variable;
std::string working_directory; std::string working_directory;
cmProcessOutput::Encoding encoding = cmProcessOutput::Auto;
for (size_t i = 0; i < args.size(); ++i) { for (size_t i = 0; i < args.size(); ++i) {
if (args[i] == "COMMAND") { if (args[i] == "COMMAND") {
doing_command = true; doing_command = true;
@@ -128,6 +129,14 @@ bool cmExecuteProcessCommand::InitialPass(std::vector<std::string> const& args,
} else if (args[i] == "ERROR_STRIP_TRAILING_WHITESPACE") { } else if (args[i] == "ERROR_STRIP_TRAILING_WHITESPACE") {
doing_command = false; doing_command = false;
error_strip_trailing_whitespace = true; error_strip_trailing_whitespace = true;
} else if (args[i] == "ENCODING") {
doing_command = false;
if (++i < args.size()) {
encoding = cmProcessOutput::FindEncoding(args[i]);
} else {
this->SetError(" called with no value for ENCODING.");
return false;
}
} else if (doing_command) { } else if (doing_command) {
cmds[command_index].push_back(args[i].c_str()); cmds[command_index].push_back(args[i].c_str());
} else { } else {
@@ -223,7 +232,7 @@ bool cmExecuteProcessCommand::InitialPass(std::vector<std::string> const& args,
int length; int length;
char* data; char* data;
int p; int p;
cmProcessOutput processOutput; cmProcessOutput processOutput(encoding);
std::string strdata; std::string strdata;
while ((p = cmsysProcess_WaitForData(cp, &data, &length, CM_NULLPTR), p)) { while ((p = cmsysProcess_WaitForData(cp, &data, &length, CM_NULLPTR), p)) {
// Put the output in the right place. // Put the output in the right place.

View File

@@ -9,6 +9,21 @@ unsigned int cmProcessOutput::defaultCodepage =
KWSYS_ENCODING_DEFAULT_CODEPAGE; KWSYS_ENCODING_DEFAULT_CODEPAGE;
#endif #endif
cmProcessOutput::Encoding cmProcessOutput::FindEncoding(std::string name)
{
Encoding encoding = Auto;
if (name == "UTF8") {
encoding = UTF8;
} else if (name == "NONE") {
encoding = None;
} else if (name == "ANSI") {
encoding = ANSI;
} else if (name == "OEM") {
encoding = OEM;
}
return encoding;
}
cmProcessOutput::cmProcessOutput(Encoding encoding, unsigned int maxSize) cmProcessOutput::cmProcessOutput(Encoding encoding, unsigned int maxSize)
{ {
#if defined(_WIN32) #if defined(_WIN32)

View File

@@ -27,6 +27,13 @@ public:
OEM OEM
}; };
/**
* Find encoding enum value for given encoding \a name.
* \param name a encoding name.
* \return encoding enum value or Auto if \a name was not found.
*/
static Encoding FindEncoding(std::string name);
/// The code page that is used as internal encoding to which we will encode. /// The code page that is used as internal encoding to which we will encode.
static unsigned int defaultCodepage; static unsigned int defaultCodepage;

View File

@@ -31,6 +31,9 @@ create_test_sourcelist(CMakeLib_TEST_SRCS CMakeLibTests.cxx ${CMakeLib_TESTS})
add_executable(CMakeLibTests ${CMakeLib_TEST_SRCS}) add_executable(CMakeLibTests ${CMakeLib_TEST_SRCS})
target_link_libraries(CMakeLibTests CMakeLib) target_link_libraries(CMakeLibTests CMakeLib)
add_executable(testEncoding testEncoding.cxx)
target_link_libraries(testEncoding cmsys)
# Xcode 2.x forgets to create the output directory before linking # Xcode 2.x forgets to create the output directory before linking
# the individual architectures. # the individual architectures.
if(CMAKE_OSX_ARCHITECTURES AND XCODE if(CMAKE_OSX_ARCHITECTURES AND XCODE

View File

@@ -0,0 +1,49 @@
#include <fstream>
#include <iostream>
#include <string>
#include <cmsys/ConsoleBuf.hxx>
#ifdef _WIN32
void setEncoding(cmsys::ConsoleBuf::Manager& buf, UINT codepage)
{
cmsys::ConsoleBuf* cb = buf.GetConsoleBuf();
if (cb) {
cb->input_pipe_codepage = codepage;
cb->output_pipe_codepage = codepage;
cb->input_file_codepage = codepage;
cb->output_file_codepage = codepage;
cb->activateCodepageChange();
}
}
#endif
int main(int argc, char* argv[])
{
#ifdef _WIN32
cmsys::ConsoleBuf::Manager consoleOut(std::cout);
#endif
if (argc <= 2) {
std::cout << "Usage: testEncoding <encoding> <file>" << std::endl;
return 1;
}
const std::string encoding(argv[1]);
#ifdef _WIN32
if (encoding == "UTF8") {
setEncoding(consoleOut, CP_UTF8);
} else if (encoding == "ANSI") {
setEncoding(consoleOut, CP_ACP);
} else if (encoding == "OEM") {
setEncoding(consoleOut, CP_OEMCP);
} // else AUTO
#endif
std::ifstream file(argv[2]);
if (!file.is_open()) {
std::cout << "Failed to open file: " << argv[2] << std::endl;
return 2;
}
std::string text((std::istreambuf_iterator<char>(file)),
std::istreambuf_iterator<char>());
std::cout << text;
return 0;
}

View File

@@ -179,6 +179,9 @@ add_RunCMake_test(add_custom_target)
add_RunCMake_test(add_dependencies) add_RunCMake_test(add_dependencies)
add_RunCMake_test(add_subdirectory) add_RunCMake_test(add_subdirectory)
add_RunCMake_test(build_command) add_RunCMake_test(build_command)
if(NOT CMake_TEST_EXTERNAL_CMAKE)
set(execute_process_ARGS -DTEST_ENCODING_EXE=$<TARGET_FILE:testEncoding>)
endif()
add_RunCMake_test(execute_process) add_RunCMake_test(execute_process)
add_RunCMake_test(export) add_RunCMake_test(export)
add_RunCMake_test(cmake_minimum_required) add_RunCMake_test(cmake_minimum_required)

View File

@@ -75,6 +75,7 @@ function(run_cmake test)
OUTPUT_VARIABLE actual_stdout OUTPUT_VARIABLE actual_stdout
ERROR_VARIABLE ${actual_stderr_var} ERROR_VARIABLE ${actual_stderr_var}
RESULT_VARIABLE actual_result RESULT_VARIABLE actual_result
ENCODING UTF8
${maybe_timeout} ${maybe_timeout}
) )
else() else()
@@ -90,6 +91,7 @@ function(run_cmake test)
OUTPUT_VARIABLE actual_stdout OUTPUT_VARIABLE actual_stdout
ERROR_VARIABLE ${actual_stderr_var} ERROR_VARIABLE ${actual_stderr_var}
RESULT_VARIABLE actual_result RESULT_VARIABLE actual_result
ENCODING UTF8
${maybe_timeout} ${maybe_timeout}
) )
endif() endif()

View File

@@ -0,0 +1,3 @@
cmake_minimum_required(VERSION 3.7)
project(${RunCMake_TEST} NONE)
include(${RunCMake_TEST}.cmake)

View File

@@ -0,0 +1,6 @@
execute_process(
COMMAND ${TEST_ENCODING_EXE} ${TEST_ENCODING} ${CMAKE_CURRENT_LIST_DIR}/EncodingUTF8-stderr.txt
OUTPUT_VARIABLE out
ENCODING ${TEST_ENCODING}
)
message("${out}")

View File

@@ -0,0 +1 @@
1

View File

@@ -0,0 +1,4 @@
^CMake Error at EncodingMissing.cmake:[0-9]+ \(execute_process\):
execute_process called with no value for ENCODING.
Call Stack \(most recent call first\):
CMakeLists.txt:[0-9]+ \(include\)$

View File

@@ -0,0 +1 @@
execute_process(ENCODING)

View File

@@ -0,0 +1 @@
यूनिकोड είναι very здорово!

View File

@@ -6,3 +6,8 @@ unset(RunCMake_TEST_OUTPUT_MERGE)
run_cmake_command(MergeOutputFile ${CMAKE_COMMAND} -P ${RunCMake_SOURCE_DIR}/MergeOutputFile.cmake) run_cmake_command(MergeOutputFile ${CMAKE_COMMAND} -P ${RunCMake_SOURCE_DIR}/MergeOutputFile.cmake)
run_cmake_command(MergeOutputVars ${CMAKE_COMMAND} -P ${RunCMake_SOURCE_DIR}/MergeOutputVars.cmake) run_cmake_command(MergeOutputVars ${CMAKE_COMMAND} -P ${RunCMake_SOURCE_DIR}/MergeOutputVars.cmake)
run_cmake(EncodingMissing)
if(TEST_ENCODING_EXE)
run_cmake_command(EncodingUTF8 ${CMAKE_COMMAND} -DTEST_ENCODING=UTF8 -DTEST_ENCODING_EXE=${TEST_ENCODING_EXE} -P ${RunCMake_SOURCE_DIR}/Encoding.cmake)
endif()