1
0
mirror of https://github.com/Kitware/CMake.git synced 2025-10-17 15:32:10 +08:00

Teach CROSSCOMPILING_EMULATOR to support arguments

Fixes: #19321
This commit is contained in:
Marek Antoniak
2019-05-30 16:11:10 +02:00
committed by Brad King
parent 3cb5a8d9b3
commit fec441ec17
12 changed files with 129 additions and 16 deletions

View File

@@ -6,6 +6,10 @@ This command will be added as a prefix to :command:`add_test`,
:command:`add_custom_command`, and :command:`add_custom_target` commands :command:`add_custom_command`, and :command:`add_custom_target` commands
for built target system executables. for built target system executables.
If this property contains a :ref:`semicolon-separated list <CMake Language
Lists>`, then the first value is the command and remaining values are its
arguments.
This property is initialized by the value of the This property is initialized by the value of the
:variable:`CMAKE_CROSSCOMPILING_EMULATOR` variable if it is set when a target :variable:`CMAKE_CROSSCOMPILING_EMULATOR` variable if it is set when a target
is created. is created.

View File

@@ -0,0 +1,6 @@
emulator-arguments
------------------
* The :variable:`CMAKE_CROSSCOMPILING_EMULATOR` variable and corresponding
:prop_tgt:`CROSSCOMPILING_EMULATOR` target property learned to support
arguments to the emulator.

View File

@@ -5,6 +5,10 @@ This variable is only used when :variable:`CMAKE_CROSSCOMPILING` is on. It
should point to a command on the host system that can run executable built should point to a command on the host system that can run executable built
for the target system. for the target system.
If this variable contains a :ref:`semicolon-separated list <CMake Language
Lists>`, then the first value is the command and remaining values are its
arguments.
The command will be used to run :command:`try_run` generated executables, The command will be used to run :command:`try_run` generated executables,
which avoids manual population of the ``TryRunResults.cmake`` file. which avoids manual population of the ``TryRunResults.cmake`` file.

View File

@@ -75,6 +75,8 @@ cmCustomCommandGenerator::cmCustomCommandGenerator(cmCustomCommand const& cc,
cmSystemTools::CollapseFullPath(this->WorkingDirectory, build_dir); cmSystemTools::CollapseFullPath(this->WorkingDirectory, build_dir);
} }
} }
this->FillEmulatorsWithArguments();
} }
cmCustomCommandGenerator::~cmCustomCommandGenerator() cmCustomCommandGenerator::~cmCustomCommandGenerator()
@@ -87,19 +89,38 @@ unsigned int cmCustomCommandGenerator::GetNumberOfCommands() const
return static_cast<unsigned int>(this->CC.GetCommandLines().size()); return static_cast<unsigned int>(this->CC.GetCommandLines().size());
} }
const char* cmCustomCommandGenerator::GetCrossCompilingEmulator( void cmCustomCommandGenerator::FillEmulatorsWithArguments()
unsigned int c) const
{ {
if (!this->LG->GetMakefile()->IsOn("CMAKE_CROSSCOMPILING")) { if (!this->LG->GetMakefile()->IsOn("CMAKE_CROSSCOMPILING")) {
return nullptr; return;
} }
std::string const& argv0 = this->CommandLines[c][0];
cmGeneratorTarget* target = this->LG->FindGeneratorTargetToUse(argv0); for (unsigned int c = 0; c < this->GetNumberOfCommands(); ++c) {
if (target && target->GetType() == cmStateEnums::EXECUTABLE && std::string const& argv0 = this->CommandLines[c][0];
!target->IsImported()) { cmGeneratorTarget* target = this->LG->FindGeneratorTargetToUse(argv0);
return target->GetProperty("CROSSCOMPILING_EMULATOR"); if (target && target->GetType() == cmStateEnums::EXECUTABLE &&
!target->IsImported()) {
const char* emulator_property =
target->GetProperty("CROSSCOMPILING_EMULATOR");
if (!emulator_property) {
continue;
}
this->EmulatorsWithArguments.emplace_back();
cmSystemTools::ExpandListArgument(emulator_property,
this->EmulatorsWithArguments[c]);
}
} }
return nullptr; }
std::vector<std::string> cmCustomCommandGenerator::GetCrossCompilingEmulator(
unsigned int c) const
{
if (c >= this->EmulatorsWithArguments.size()) {
return std::vector<std::string>();
}
return this->EmulatorsWithArguments[c];
} }
const char* cmCustomCommandGenerator::GetArgv0Location(unsigned int c) const const char* cmCustomCommandGenerator::GetArgv0Location(unsigned int c) const
@@ -129,8 +150,9 @@ bool cmCustomCommandGenerator::HasOnlyEmptyCommandLines() const
std::string cmCustomCommandGenerator::GetCommand(unsigned int c) const std::string cmCustomCommandGenerator::GetCommand(unsigned int c) const
{ {
if (const char* emulator = this->GetCrossCompilingEmulator(c)) { std::vector<std::string> emulator = this->GetCrossCompilingEmulator(c);
return std::string(emulator); if (!emulator.empty()) {
return emulator[0];
} }
if (const char* location = this->GetArgv0Location(c)) { if (const char* location = this->GetArgv0Location(c)) {
return std::string(location); return std::string(location);
@@ -168,9 +190,20 @@ void cmCustomCommandGenerator::AppendArguments(unsigned int c,
std::string& cmd) const std::string& cmd) const
{ {
unsigned int offset = 1; unsigned int offset = 1;
if (this->GetCrossCompilingEmulator(c) != nullptr) { std::vector<std::string> emulator = this->GetCrossCompilingEmulator(c);
if (!emulator.empty()) {
for (unsigned j = 1; j < emulator.size(); ++j) {
cmd += " ";
if (this->OldStyle) {
cmd += escapeForShellOldStyle(emulator[j]);
} else {
cmd += this->LG->EscapeForShell(emulator[j], this->MakeVars);
}
}
offset = 0; offset = 0;
} }
cmCustomCommandLine const& commandLine = this->CommandLines[c]; cmCustomCommandLine const& commandLine = this->CommandLines[c];
for (unsigned int j = offset; j < commandLine.size(); ++j) { for (unsigned int j = offset; j < commandLine.size(); ++j) {
std::string arg; std::string arg;

View File

@@ -22,10 +22,12 @@ class cmCustomCommandGenerator
bool MakeVars; bool MakeVars;
cmGeneratorExpression* GE; cmGeneratorExpression* GE;
cmCustomCommandLines CommandLines; cmCustomCommandLines CommandLines;
std::vector<std::vector<std::string>> EmulatorsWithArguments;
std::vector<std::string> Depends; std::vector<std::string> Depends;
std::string WorkingDirectory; std::string WorkingDirectory;
const char* GetCrossCompilingEmulator(unsigned int c) const; void FillEmulatorsWithArguments();
std::vector<std::string> GetCrossCompilingEmulator(unsigned int c) const;
const char* GetArgv0Location(unsigned int c) const; const char* GetArgv0Location(unsigned int c) const;
public: public:

View File

@@ -448,9 +448,11 @@ endif()
add_executable(pseudo_emulator pseudo_emulator.c) add_executable(pseudo_emulator pseudo_emulator.c)
add_executable(pseudo_emulator_custom_command pseudo_emulator_custom_command.c) add_executable(pseudo_emulator_custom_command pseudo_emulator_custom_command.c)
add_executable(pseudo_emulator_custom_command_arg pseudo_emulator_custom_command_arg.c)
add_RunCMake_test(CrosscompilingEmulator add_RunCMake_test(CrosscompilingEmulator
-DPSEUDO_EMULATOR=$<TARGET_FILE:pseudo_emulator> -DPSEUDO_EMULATOR=$<TARGET_FILE:pseudo_emulator>
-DPSEUDO_EMULATOR_CUSTOM_COMMAND=$<TARGET_FILE:pseudo_emulator_custom_command>) -DPSEUDO_EMULATOR_CUSTOM_COMMAND=$<TARGET_FILE:pseudo_emulator_custom_command>
-DPSEUDO_EMULATOR_CUSTOM_COMMAND_ARG=$<TARGET_FILE:pseudo_emulator_custom_command_arg>)
if("${CMAKE_GENERATOR}" MATCHES "Make|Ninja") if("${CMAKE_GENERATOR}" MATCHES "Make|Ninja")
if(UNIX AND NOT CYGWIN) if(UNIX AND NOT CYGWIN)
execute_process(COMMAND ldd --help execute_process(COMMAND ldd --help

View File

@@ -0,0 +1,3 @@
if(NOT EXISTS "${RunCMake_TEST_BINARY_DIR}/output")
message(FATAL_ERROR "Failed to create output: ${RunCMake_TEST_BINARY_DIR}/output")
endif()

View File

@@ -0,0 +1,14 @@
set(CMAKE_CROSSCOMPILING 1)
# Executable: Return error code different from 0
add_executable(generated_exe_emulator_expected simple_src_exiterror.cxx)
add_custom_command(OUTPUT output
COMMAND generated_exe_emulator_expected
COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_CURRENT_BINARY_DIR}/output
DEPENDS generated_exe_emulator_expected)
add_custom_target(ensure_build ALL
SOURCES
${CMAKE_CURRENT_BINARY_DIR}/output
)

View File

@@ -0,0 +1 @@
include(${CMAKE_CURRENT_LIST_DIR}/AddCustomCommandWithArg-build-check.cmake)

View File

@@ -0,0 +1,9 @@
set(CMAKE_CROSSCOMPILING 1)
# Executable: Return error code different from 0
add_executable(generated_exe_emulator_expected simple_src_exiterror.cxx)
add_custom_target(generate_output ALL
generated_exe_emulator_expected
COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_CURRENT_BINARY_DIR}/output
DEPENDS generated_exe_emulator_expected)

View File

@@ -11,13 +11,18 @@ function(CustomCommandGenerator_run_and_build case)
# Use a single build tree for a few tests without cleaning. # Use a single build tree for a few tests without cleaning.
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${case}-build) set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${case}-build)
set(RunCMake_TEST_NO_CLEAN 1) set(RunCMake_TEST_NO_CLEAN 1)
set(RunCMake_TEST_OPTIONS
"-DCMAKE_CROSSCOMPILING_EMULATOR=${PSEUDO_EMULATOR_CUSTOM_COMMAND}")
file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}") file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}") file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
run_cmake(${case}) run_cmake(${case})
run_cmake_command(${case}-build ${CMAKE_COMMAND} --build .) run_cmake_command(${case}-build ${CMAKE_COMMAND} --build .)
endfunction() endfunction()
set(RunCMake_TEST_OPTIONS
"-DCMAKE_CROSSCOMPILING_EMULATOR=${PSEUDO_EMULATOR_CUSTOM_COMMAND}")
CustomCommandGenerator_run_and_build(AddCustomCommand) CustomCommandGenerator_run_and_build(AddCustomCommand)
CustomCommandGenerator_run_and_build(AddCustomTarget) CustomCommandGenerator_run_and_build(AddCustomTarget)
set(RunCMake_TEST_OPTIONS
"-DCMAKE_CROSSCOMPILING_EMULATOR=${PSEUDO_EMULATOR_CUSTOM_COMMAND_ARG}\;custom_argument")
CustomCommandGenerator_run_and_build(AddCustomCommandWithArg)
CustomCommandGenerator_run_and_build(AddCustomTargetWithArg)

View File

@@ -0,0 +1,30 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// Usage:
//
// /path/to/program arg1 [arg2 [...]]
//
// Return EXIT_SUCCESS if 'custom_argument' string was found
// in <arg1> and 'generated_exe_emulator_expected'
// string was found in <arg2>
// Return EXIT_FAILURE if 'custom_argument' string was not
// found in <arg1> or 'generated_exe_emulator_expected'
// string was not found in <arg2>.
int main(int argc, const char* argv[])
{
// Require a slash to make sure it is a path and not a target name.
const char* substring_success = "/generated_exe_emulator_expected";
const char* substring_custom_argument = "custom_argument";
if (argc < 2) {
return EXIT_FAILURE;
}
if (strstr(argv[1], substring_custom_argument) != 0 &&
strstr(argv[2], substring_success) != 0) {
return EXIT_SUCCESS;
}
return EXIT_FAILURE;
}