mirror of
https://github.com/Kitware/CMake.git
synced 2025-10-20 21:40:15 +08:00
execute_process: Add ENCODING option for Windows child process output
Different applications can use different output encodings.
This commit is contained in:
@@ -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
|
||||||
|
5
Help/release/dev/execute_process-encoding.rst
Normal file
5
Help/release/dev/execute_process-encoding.rst
Normal 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.
|
@@ -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.
|
||||||
|
@@ -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)
|
||||||
|
@@ -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;
|
||||||
|
|
||||||
|
@@ -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
|
||||||
|
49
Tests/CMakeLib/testEncoding.cxx
Normal file
49
Tests/CMakeLib/testEncoding.cxx
Normal 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;
|
||||||
|
}
|
@@ -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)
|
||||||
|
@@ -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()
|
||||||
|
3
Tests/RunCMake/execute_process/CMakeLists.txt
Normal file
3
Tests/RunCMake/execute_process/CMakeLists.txt
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.7)
|
||||||
|
project(${RunCMake_TEST} NONE)
|
||||||
|
include(${RunCMake_TEST}.cmake)
|
6
Tests/RunCMake/execute_process/Encoding.cmake
Normal file
6
Tests/RunCMake/execute_process/Encoding.cmake
Normal 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}")
|
@@ -0,0 +1 @@
|
|||||||
|
1
|
@@ -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\)$
|
1
Tests/RunCMake/execute_process/EncodingMissing.cmake
Normal file
1
Tests/RunCMake/execute_process/EncodingMissing.cmake
Normal file
@@ -0,0 +1 @@
|
|||||||
|
execute_process(ENCODING)
|
1
Tests/RunCMake/execute_process/EncodingUTF8-stderr.txt
Normal file
1
Tests/RunCMake/execute_process/EncodingUTF8-stderr.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
यूनिकोड είναι very здорово!
|
@@ -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()
|
||||||
|
Reference in New Issue
Block a user