Launchers: Support setting linker launchers

Fixes: #18316
This commit is contained in:
Bobby D Reynolds
2021-05-18 08:57:02 -07:00
committed by Brad King
parent 92c8b83641
commit ae108418ae
63 changed files with 261 additions and 1 deletions

View File

@@ -905,6 +905,7 @@ syn keyword cmakeVariable contained
\ CMAKE_CXX_INCLUDE_WHAT_YOU_USE
\ CMAKE_CXX_INIT
\ CMAKE_CXX_LIBRARY_ARCHITECTURE
\ CMAKE_CXX_LINKER_LAUNCHER
\ CMAKE_CXX_LINKER_PREFERENCE
\ CMAKE_CXX_LINKER_PREFERENCE_PROPAGATES
\ CMAKE_CXX_LINKER_WRAPPER_FLAG
@@ -970,6 +971,7 @@ syn keyword cmakeVariable contained
\ CMAKE_C_INCLUDE_WHAT_YOU_USE
\ CMAKE_C_INIT
\ CMAKE_C_LIBRARY_ARCHITECTURE
\ CMAKE_C_LINKER_LAUNCHER
\ CMAKE_C_LINKER_PREFERENCE
\ CMAKE_C_LINKER_PREFERENCE_PROPAGATES
\ CMAKE_C_LINKER_WRAPPER_FLAG
@@ -1263,10 +1265,12 @@ syn keyword cmakeVariable contained
\ CMAKE_NO_SYSTEM_FROM_IMPORTED
\ CMAKE_OBJCXX_CLANG_TIDY
\ CMAKE_OBJCXX_EXTENSIONS
\ CMAKE_OBJCXX_LINKER_LAUNCHER
\ CMAKE_OBJCXX_STANDARD
\ CMAKE_OBJCXX_STANDARD_REQUIRED
\ CMAKE_OBJC_CLANG_TIDY
\ CMAKE_OBJC_EXTENSIONS
\ CMAKE_OBJC_LINKER_LAUNCHER
\ CMAKE_OBJC_STANDARD
\ CMAKE_OBJC_STANDARD_REQUIRED
\ CMAKE_OBJECT_PATH_MAX

View File

@@ -0,0 +1,13 @@
CMAKE_<LANG>_LINKER_LAUNCHER
----------------------------
.. versionadded:: 3.21
.. include:: ENV_VAR.txt
Default launcher to use when linking a target of the specified language. Will
only be used by CMake to initialize the variable on the first configuration.
Afterwards, it is available through the cache setting of the variable of the
same name. For any configuration run (including the first), the environment
variable will be ignored if the :variable:`CMAKE_<LANG>_LINKER_LAUNCHER`
variable is defined.

View File

@@ -37,6 +37,7 @@ Environment Variables that Control the Build
/envvar/CMAKE_GENERATOR_PLATFORM
/envvar/CMAKE_GENERATOR_TOOLSET
/envvar/CMAKE_LANG_COMPILER_LAUNCHER
/envvar/CMAKE_LANG_LINKER_LAUNCHER
/envvar/CMAKE_MSVCIDE_RUN_PATH
/envvar/CMAKE_NO_VERBOSE
/envvar/CMAKE_OSX_ARCHITECTURES

View File

@@ -272,6 +272,7 @@ Properties on Targets
/prop_tgt/LANG_CPPCHECK
/prop_tgt/LANG_CPPLINT
/prop_tgt/LANG_INCLUDE_WHAT_YOU_USE
/prop_tgt/LANG_LINKER_LAUNCHER
/prop_tgt/LANG_VISIBILITY_PRESET
/prop_tgt/LIBRARY_OUTPUT_DIRECTORY
/prop_tgt/LIBRARY_OUTPUT_DIRECTORY_CONFIG

View File

@@ -424,6 +424,7 @@ Variables that Control the Build
/variable/CMAKE_LANG_CPPCHECK
/variable/CMAKE_LANG_CPPLINT
/variable/CMAKE_LANG_INCLUDE_WHAT_YOU_USE
/variable/CMAKE_LANG_LINKER_LAUNCHER
/variable/CMAKE_LANG_LINK_LIBRARY_FILE_FLAG
/variable/CMAKE_LANG_LINK_LIBRARY_FLAG
/variable/CMAKE_LANG_VISIBILITY_PRESET

View File

@@ -0,0 +1,16 @@
<LANG>_LINKER_LAUNCHER
----------------------
.. versionadded:: 3.21
This property is implemented only when ``<LANG>`` is ``C``, ``CXX``,
``OBJC``, or ``OBJCXX``
Specify a :ref:`semicolon-separated list <CMake Language Lists>` containing a
command line for a linker launching tool. The :ref:`Makefile Generators` and the
:generator:`Ninja` generator will run this tool and pass the linker and its
arguments to the tool. This is useful for tools such as static analyzers.
This property is initialized by the value of the
:variable:`CMAKE_<LANG>_LINKER_LAUNCHER` variable if it is set when a target is
created.

View File

@@ -0,0 +1,7 @@
linker-launcher
---------------
* The :ref:`Makefile Generators` and the :generator:`Ninja` generator learned to
add linker launcher tools along with the linker for ``C``, ``CXX``, ``OBJC``, and
``OBJCXX`` languages. See the :variable:`CMAKE_<LANG>_LINKER_LAUNCHER` variable
and :prop_tgt:`<LANG>_LINKER_LAUNCHER` target property for details.

View File

@@ -0,0 +1,11 @@
CMAKE_<LANG>_LINKER_LAUNCHER
----------------------------
.. versionadded:: 3.21
Default value for :prop_tgt:`<LANG>_LINKER_LAUNCHER` target property. This
variable is used to initialize the property on each target as it is created.
This is done only when ``<LANG>`` is ``C``, ``CXX``, ``OBJC``, or ``OBJCXX``.
This variable is initialized to the :envvar:`CMAKE_<LANG>_LINKER_LAUNCHER`
environment variable if it is set.

View File

@@ -115,6 +115,11 @@ if(NOT CMAKE_C_COMPILER_LAUNCHER AND DEFINED ENV{CMAKE_C_COMPILER_LAUNCHER})
CACHE STRING "Compiler launcher for C.")
endif()
if(NOT CMAKE_C_LINKER_LAUNCHER AND DEFINED ENV{CMAKE_C_LINKER_LAUNCHER})
set(CMAKE_C_LINKER_LAUNCHER "$ENV{CMAKE_C_LINKER_LAUNCHER}"
CACHE STRING "Linker launcher for C.")
endif()
include(CMakeCommonLanguageInclude)
# now define the following rule variables

View File

@@ -212,6 +212,11 @@ if(NOT CMAKE_CXX_COMPILER_LAUNCHER AND DEFINED ENV{CMAKE_CXX_COMPILER_LAUNCHER})
CACHE STRING "Compiler launcher for CXX.")
endif()
if(NOT CMAKE_CXX_LINKER_LAUNCHER AND DEFINED ENV{CMAKE_CXX_LINKER_LAUNCHER})
set(CMAKE_CXX_LINKER_LAUNCHER "$ENV{CMAKE_CXX_LINKER_LAUNCHER}"
CACHE STRING "Linker launcher for CXX.")
endif()
include(CMakeCommonLanguageInclude)
# now define the following rules:

View File

@@ -115,6 +115,11 @@ if(NOT CMAKE_OBJC_COMPILER_LAUNCHER AND DEFINED ENV{CMAKE_OBJC_COMPILER_LAUNCHER
CACHE STRING "Compiler launcher for OBJC.")
endif()
if(NOT CMAKE_OBJC_LINKER_LAUNCHER AND DEFINED ENV{CMAKE_OBJC_LINKER_LAUNCHER})
set(CMAKE_OBJC_LINKER_LAUNCHER "$ENV{CMAKE_OBJC_LINKER_LAUNCHER}"
CACHE STRING "Linker launcher for OBJC.")
endif()
include(CMakeCommonLanguageInclude)
# now define the following rule variables

View File

@@ -208,6 +208,11 @@ if(NOT CMAKE_OBJCXX_COMPILER_LAUNCHER AND DEFINED ENV{CMAKE_OBJCXX_COMPILER_LAUN
CACHE STRING "Compiler launcher for OBJCXX.")
endif()
if(NOT CMAKE_OBJCXX_LINKER_LAUNCHER AND DEFINED ENV{CMAKE_OBJCXX_LINKER_LAUNCHER})
set(CMAKE_OBJCXX_LINKER_LAUNCHER "$ENV{CMAKE_OBJCXX_LINKER_LAUNCHER}"
CACHE STRING "Linker launcher for OBJCXX.")
endif()
include(CMakeCommonLanguageInclude)
# now define the following rules:

View File

@@ -15,6 +15,7 @@
#include "cmMakefile.h"
#include "cmOutputConverter.h"
#include "cmProperty.h"
#include "cmRange.h"
#include "cmSourceFile.h"
#include "cmStateTypes.h"
#include "cmStringAlgorithms.h"
@@ -291,3 +292,24 @@ void cmCommonTargetGenerator::AppendOSXVerFlag(std::string& flags,
this->LocalCommonGenerator->AppendFlags(flags, vflag.str());
}
}
std::string cmCommonTargetGenerator::GetLinkerLauncher(
const std::string& config)
{
std::string lang = this->GeneratorTarget->GetLinkerLanguage(config);
cmProp launcherProp =
this->GeneratorTarget->GetProperty(lang + "_LINKER_LAUNCHER");
if (cmNonempty(launcherProp)) {
// Convert ;-delimited list to single string
std::vector<std::string> args = cmExpandedList(*launcherProp, true);
if (!args.empty()) {
args[0] = this->LocalCommonGenerator->ConvertToOutputFormat(
args[0], cmOutputConverter::SHELL);
for (std::string& i : cmMakeRange(args.begin() + 1, args.end())) {
i = this->LocalCommonGenerator->EscapeForShell(i);
}
return cmJoin(args, " ");
}
}
return std::string();
}

View File

@@ -64,6 +64,8 @@ protected:
const std::string& config) const;
std::string ComputeTargetCompilePDB(const std::string& config) const;
std::string GetLinkerLauncher(const std::string& config);
private:
using ByLanguageMap = std::map<std::string, std::string>;
struct ByConfig

View File

@@ -571,6 +571,12 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink)
vars.LinkFlags = linkFlags.c_str();
vars.Manifests = manifests.c_str();
std::string linkerLauncher =
this->GetLinkerLauncher(this->GetConfigName());
if (cmNonempty(linkerLauncher)) {
vars.Launcher = linkerLauncher.c_str();
}
if (this->GeneratorTarget->GetPropertyAsBool("LINK_WHAT_YOU_USE")) {
std::string cmakeCommand =
cmStrCat(this->LocalGenerator->ConvertToOutputFormat(

View File

@@ -804,6 +804,12 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules(
vars.LanguageCompileFlags = langFlags.c_str();
std::string linkerLauncher =
this->GetLinkerLauncher(this->GetConfigName());
if (cmNonempty(linkerLauncher)) {
vars.Launcher = linkerLauncher.c_str();
}
std::string launcher;
cmProp val = this->LocalGenerator->GetRuleLauncher(this->GeneratorTarget,
"RULE_LAUNCH_LINK");

View File

@@ -456,6 +456,11 @@ void cmNinjaNormalTargetGenerator::WriteLinkRule(bool useResponseFile,
vars.LanguageCompileFlags = langFlags.c_str();
}
std::string linkerLauncher = this->GetLinkerLauncher(config);
if (cmNonempty(linkerLauncher)) {
vars.Launcher = linkerLauncher.c_str();
}
std::string launcher;
cmProp val = this->GetLocalGenerator()->GetRuleLauncher(
this->GetGeneratorTarget(), "RULE_LAUNCH_LINK");

View File

@@ -6,6 +6,7 @@
#include <utility>
#include "cmOutputConverter.h"
#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"
cmRulePlaceholderExpander::cmRulePlaceholderExpander(
@@ -280,6 +281,13 @@ std::string cmRulePlaceholderExpander::ExpandRuleVariable(
this->VariableMappings["CMAKE_" + compIt->second +
"_COMPILE_OPTIONS_SYSROOT"];
if (compIt->second == replaceValues.Language && replaceValues.Launcher) {
// Add launcher as part of expansion so that it always appears
// immediately before the command itself, regardless of whether the
// overall rule template contains other content at the front.
ret = cmStrCat(replaceValues.Launcher, " ", ret);
}
// if there are required arguments to the compiler add it
// to the compiler string
if (!compilerArg1.empty()) {
@@ -317,7 +325,17 @@ std::string cmRulePlaceholderExpander::ExpandRuleVariable(
auto mapIt = this->VariableMappings.find(variable);
if (mapIt != this->VariableMappings.end()) {
if (variable.find("_FLAG") == std::string::npos) {
return outputConverter->ConvertToOutputForExisting(mapIt->second);
std::string ret =
outputConverter->ConvertToOutputForExisting(mapIt->second);
if (replaceValues.Launcher && variable == "CMAKE_LINKER") {
// Add launcher as part of expansion so that it always appears
// immediately before the command itself, regardless of whether the
// overall rule template contains other content at the front.
ret = cmStrCat(replaceValues.Launcher, " ", ret);
}
return ret;
}
return mapIt->second;
}

View File

@@ -67,6 +67,7 @@ public:
const char* ISPCHeader = nullptr;
const char* Fatbinary = nullptr;
const char* RegisterFile = nullptr;
const char* Launcher = nullptr;
};
// Expand rule variables in CMake of the type found in language rules

View File

@@ -354,11 +354,13 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type,
initProp("C_CPPLINT");
initProp("C_CPPCHECK");
initProp("C_INCLUDE_WHAT_YOU_USE");
initProp("C_LINKER_LAUNCHER");
initProp("LINK_WHAT_YOU_USE");
initProp("CXX_CLANG_TIDY");
initProp("CXX_CPPLINT");
initProp("CXX_CPPCHECK");
initProp("CXX_INCLUDE_WHAT_YOU_USE");
initProp("CXX_LINKER_LAUNCHER");
initProp("CUDA_SEPARABLE_COMPILATION");
initProp("CUDA_RESOLVE_DEVICE_SYMBOLS");
initProp("CUDA_RUNTIME_LIBRARY");
@@ -374,7 +376,9 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type,
initProp("LINK_SEARCH_START_STATIC");
initProp("LINK_SEARCH_END_STATIC");
initProp("OBJC_CLANG_TIDY");
initProp("OBJC_LINKER_LAUNCHER");
initProp("OBJCXX_CLANG_TIDY");
initProp("OBJCXX_LINKER_LAUNCHER");
initProp("Swift_LANGUAGE_VERSION");
initProp("Swift_MODULE_DIRECTORY");
initProp("VS_JUST_MY_CODE_DEBUGGING");

View File

@@ -732,12 +732,14 @@ if("${CMAKE_GENERATOR}" MATCHES "Make|Ninja")
endif()
if (APPLE AND CMAKE_C_COMPILER_ID MATCHES "Clang|GNU")
list(APPEND CompilerLauncher_ARGS -DCMake_TEST_OBJC=1)
list(APPEND LinkerLauncher_ARGS -DCMake_TEST_OBJC=1)
endif()
add_RunCMake_test(CompilerLauncher)
set_property(TEST RunCMake.CompilerLauncher APPEND
PROPERTY LABELS "CUDA;ISPC")
add_RunCMake_test(ctest_labels_for_subprojects)
add_RunCMake_test(CompilerArgs)
add_RunCMake_test(LinkerLauncher)
endif()
set(cpack_tests

View File

@@ -0,0 +1 @@
.*-E env USED_LAUNCHER=1.*

View File

@@ -0,0 +1,3 @@
enable_language(C)
set(CMAKE_VERBOSE_MAKEFILE TRUE)
add_executable(main main.c)

View File

@@ -0,0 +1 @@
.*-E env USED_LAUNCHER=1.*

View File

@@ -0,0 +1 @@
include(C-common.cmake)

View File

@@ -0,0 +1 @@
.*-E env USED_LAUNCHER=1.*

View File

@@ -0,0 +1 @@
.*-E env USED_LAUNCHER=1.*

View File

@@ -0,0 +1,3 @@
set(CTEST_USE_LAUNCHERS 1)
include(CTestUseLaunchers)
include(C-env.cmake)

View File

@@ -0,0 +1,3 @@
set(CTEST_USE_LAUNCHERS 1)
include(CTestUseLaunchers)
include(C.cmake)

View File

@@ -0,0 +1,2 @@
set(CMAKE_C_LINKER_LAUNCHER "${CMAKE_COMMAND};-E;env;USED_LAUNCHER=1")
include(C-common.cmake)

View File

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

View File

@@ -0,0 +1 @@
.*-E env USED_LAUNCHER=1.*

View File

@@ -0,0 +1,3 @@
enable_language(CXX)
set(CMAKE_VERBOSE_MAKEFILE TRUE)
add_executable(main main.cxx)

View File

@@ -0,0 +1 @@
.*-E env USED_LAUNCHER=1.*

View File

@@ -0,0 +1 @@
include(CXX-common.cmake)

View File

@@ -0,0 +1 @@
.*-E env USED_LAUNCHER=1.*

View File

@@ -0,0 +1 @@
.*-E env USED_LAUNCHER=1.*

View File

@@ -0,0 +1,3 @@
set(CTEST_USE_LAUNCHERS 1)
include(CTestUseLaunchers)
include(CXX-env.cmake)

View File

@@ -0,0 +1,3 @@
set(CTEST_USE_LAUNCHERS 1)
include(CTestUseLaunchers)
include(CXX.cmake)

View File

@@ -0,0 +1,2 @@
set(CMAKE_CXX_LINKER_LAUNCHER "${CMAKE_COMMAND};-E;env;USED_LAUNCHER=1")
include(CXX-common.cmake)

View File

@@ -0,0 +1 @@
.*-E env USED_LAUNCHER=1.*

View File

@@ -0,0 +1,3 @@
enable_language(OBJC)
set(CMAKE_VERBOSE_MAKEFILE TRUE)
add_executable(main main.m)

View File

@@ -0,0 +1 @@
.*-E env USED_LAUNCHER=1.*

View File

@@ -0,0 +1 @@
include(OBJC-common.cmake)

View File

@@ -0,0 +1 @@
.*-E env USED_LAUNCHER=1.*

View File

@@ -0,0 +1 @@
.*-E env USED_LAUNCHER=1.*

View File

@@ -0,0 +1,3 @@
set(CTEST_USE_LAUNCHERS 1)
include(CTestUseLaunchers)
include(OBJC-env.cmake)

View File

@@ -0,0 +1,3 @@
set(CTEST_USE_LAUNCHERS 1)
include(CTestUseLaunchers)
include(OBJC.cmake)

View File

@@ -0,0 +1,2 @@
set(CMAKE_OBJC_LINKER_LAUNCHER "${CMAKE_COMMAND};-E;env;USED_LAUNCHER=1")
include(OBJC-common.cmake)

View File

@@ -0,0 +1 @@
.*-E env USED_LAUNCHER=1.*

View File

@@ -0,0 +1,3 @@
enable_language(OBJCXX)
set(CMAKE_VERBOSE_MAKEFILE TRUE)
add_executable(main main.mm)

View File

@@ -0,0 +1 @@
.*-E env USED_LAUNCHER=1.*

View File

@@ -0,0 +1 @@
include(OBJCXX-common.cmake)

View File

@@ -0,0 +1 @@
.*-E env USED_LAUNCHER=1.*

View File

@@ -0,0 +1 @@
.*-E env USED_LAUNCHER=1.*

View File

@@ -0,0 +1,3 @@
set(CTEST_USE_LAUNCHERS 1)
include(CTestUseLaunchers)
include(OBJCXX-env.cmake)

View File

@@ -0,0 +1,3 @@
set(CTEST_USE_LAUNCHERS 1)
include(CTestUseLaunchers)
include(OBJCXX.cmake)

View File

@@ -0,0 +1,2 @@
set(CMAKE_OBJCXX_LINKER_LAUNCHER "${CMAKE_COMMAND};-E;env;USED_LAUNCHER=1")
include(OBJCXX-common.cmake)

View File

@@ -0,0 +1,37 @@
include(RunCMake)
function(run_linker_launcher lang)
# Preserve build tree so we can reuse it for the ${lang}-Build subtest below
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${lang}-build)
set(RunCMake_TEST_NO_CLEAN 1)
file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
run_cmake(${lang})
set(RunCMake_TEST_OUTPUT_MERGE 1)
if("${RunCMake_GENERATOR}" MATCHES "Ninja")
set(verbose_args -- -v)
endif()
run_cmake_command(${lang}-Build ${CMAKE_COMMAND} --build . ${verbose_args})
endfunction()
function(run_linker_launcher_env lang)
string(REGEX REPLACE "-.*" "" core_lang "${lang}")
set(ENV{CMAKE_${core_lang}_LINKER_LAUNCHER} "${CMAKE_COMMAND};-E;env;USED_LAUNCHER=1")
run_linker_launcher(${lang})
unset(ENV{CMAKE_${core_lang}_LINKER_LAUNCHER})
endfunction()
set(langs C CXX)
if(CMake_TEST_OBJC)
list(APPEND langs OBJC OBJCXX)
endif()
foreach(lang ${langs})
run_linker_launcher(${lang})
run_linker_launcher_env(${lang}-env)
if(NOT RunCMake_GENERATOR STREQUAL "Watcom WMake")
run_linker_launcher(${lang}-launch)
run_linker_launcher_env(${lang}-launch-env)
endif()
endforeach()

View File

@@ -0,0 +1,4 @@
int main(void)
{
return 0;
}

View File

@@ -0,0 +1,4 @@
int main()
{
return 0;
}

View File

@@ -0,0 +1,4 @@
int main(void)
{
return 0;
}

View File

@@ -0,0 +1,4 @@
int main()
{
return 0;
}