From 023de565d33cdb095c0d5665e408493087e4d458 Mon Sep 17 00:00:00 2001 From: Brad King Date: Thu, 25 May 2023 11:59:26 -0400 Subject: Optionally exclude implicit link directories via environment A misconfigured compiler may pass extraneous implicit link directories to its linker. If they are in `CMAKE__IMPLICIT_LINK_DIRECTORIES`, CMake may generate extra `-L` flags on mixed-language link lines that break linking. Add an environment variable that users can set to work around such misconfiguration of their compilers. --- .../envvar/CMAKE_LANG_IMPLICIT_LINK_DIRECTORIES_EXCLUDE.rst | 13 +++++++++++++ Help/manual/cmake-env-variables.7.rst | 1 + Help/variable/CMAKE_LANG_IMPLICIT_LINK_DIRECTORIES.rst | 7 ++++++- Modules/CMakeDetermineCompilerABI.cmake | 4 ++++ Tests/RunCMake/ParseImplicitLinkInfo/ExcludeDirs.cmake | 10 ++++++++++ Tests/RunCMake/ParseImplicitLinkInfo/Inspect.cmake | 12 ++++++++++++ Tests/RunCMake/ParseImplicitLinkInfo/RunCMakeTest.cmake | 8 ++++++++ 7 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 Help/envvar/CMAKE_LANG_IMPLICIT_LINK_DIRECTORIES_EXCLUDE.rst create mode 100644 Tests/RunCMake/ParseImplicitLinkInfo/ExcludeDirs.cmake create mode 100644 Tests/RunCMake/ParseImplicitLinkInfo/Inspect.cmake diff --git a/Help/envvar/CMAKE_LANG_IMPLICIT_LINK_DIRECTORIES_EXCLUDE.rst b/Help/envvar/CMAKE_LANG_IMPLICIT_LINK_DIRECTORIES_EXCLUDE.rst new file mode 100644 index 0000000..36c79fa --- /dev/null +++ b/Help/envvar/CMAKE_LANG_IMPLICIT_LINK_DIRECTORIES_EXCLUDE.rst @@ -0,0 +1,13 @@ +CMAKE__IMPLICIT_LINK_DIRECTORIES_EXCLUDE +---------------------------------------------- + +.. versionadded:: 3.27 + +.. include:: ENV_VAR.txt + +A :ref:`semicolon-separated list ` of directories +to exclude from the :variable:`CMAKE__IMPLICIT_LINK_DIRECTORIES` +variable when it is automatically detected from the ```` compiler. + +This may be used to work around misconfigured compiler drivers that pass +extraneous implicit link directories to their linker. diff --git a/Help/manual/cmake-env-variables.7.rst b/Help/manual/cmake-env-variables.7.rst index f7ae94d..197e56e 100644 --- a/Help/manual/cmake-env-variables.7.rst +++ b/Help/manual/cmake-env-variables.7.rst @@ -50,6 +50,7 @@ Environment Variables that Control the Build /envvar/CMAKE_GENERATOR_TOOLSET /envvar/CMAKE_INSTALL_MODE /envvar/CMAKE_LANG_COMPILER_LAUNCHER + /envvar/CMAKE_LANG_IMPLICIT_LINK_DIRECTORIES_EXCLUDE /envvar/CMAKE_LANG_LINKER_LAUNCHER /envvar/CMAKE_MSVCIDE_RUN_PATH /envvar/CMAKE_NO_VERBOSE diff --git a/Help/variable/CMAKE_LANG_IMPLICIT_LINK_DIRECTORIES.rst b/Help/variable/CMAKE_LANG_IMPLICIT_LINK_DIRECTORIES.rst index 081c4da..7e008df 100644 --- a/Help/variable/CMAKE_LANG_IMPLICIT_LINK_DIRECTORIES.rst +++ b/Help/variable/CMAKE_LANG_IMPLICIT_LINK_DIRECTORIES.rst @@ -6,9 +6,14 @@ Implicit linker search path detected for language ````. Compilers typically pass directories containing language runtime libraries and default library search paths when they invoke a linker. These paths are implicit linker search directories for the compiler's -language. For each language enabled by the :command:`project` or +language. + +For each language enabled by the :command:`project` or :command:`enable_language` command, CMake automatically detects these directories and reports the results in this variable. +The :envvar:`CMAKE__IMPLICIT_LINK_DIRECTORIES_EXCLUDE` environment +variable may be set to exclude specific directories from the automatically +detected results. When linking to a static library, CMake adds the implicit link directories from this variable for each language used in the static library (except diff --git a/Modules/CMakeDetermineCompilerABI.cmake b/Modules/CMakeDetermineCompilerABI.cmake index 3fd54cc..d665cd1 100644 --- a/Modules/CMakeDetermineCompilerABI.cmake +++ b/Modules/CMakeDetermineCompilerABI.cmake @@ -181,6 +181,10 @@ function(CMAKE_DETERMINE_COMPILER_ABI lang src) endif() endif() + if(DEFINED ENV{CMAKE_${lang}_IMPLICIT_LINK_DIRECTORIES_EXCLUDE}) + list(REMOVE_ITEM implicit_dirs $ENV{CMAKE_${lang}_IMPLICIT_LINK_DIRECTORIES_EXCLUDE}) + endif() + set(CMAKE_${lang}_IMPLICIT_LINK_LIBRARIES "${implicit_libs}" PARENT_SCOPE) set(CMAKE_${lang}_IMPLICIT_LINK_DIRECTORIES "${implicit_dirs}" PARENT_SCOPE) set(CMAKE_${lang}_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES "${implicit_fwks}" PARENT_SCOPE) diff --git a/Tests/RunCMake/ParseImplicitLinkInfo/ExcludeDirs.cmake b/Tests/RunCMake/ParseImplicitLinkInfo/ExcludeDirs.cmake new file mode 100644 index 0000000..6cece68 --- /dev/null +++ b/Tests/RunCMake/ParseImplicitLinkInfo/ExcludeDirs.cmake @@ -0,0 +1,10 @@ +include("${info}") +list(GET INFO_CMAKE_C_IMPLICIT_LINK_DIRECTORIES -1 last_dir) +set(ENV{CMAKE_C_IMPLICIT_LINK_DIRECTORIES_EXCLUDE} "${last_dir}") +enable_language(C) +message(STATUS "INFO_CMAKE_C_IMPLICIT_LINK_DIRECTORIES=[${INFO_CMAKE_C_IMPLICIT_LINK_DIRECTORIES}]") +message(STATUS "ENV{CMAKE_C_IMPLICIT_LINK_DIRECTORIES_EXCLUDE}=[$ENV{CMAKE_C_IMPLICIT_LINK_DIRECTORIES_EXCLUDE}]") +message(STATUS "CMAKE_C_IMPLICIT_LINK_DIRECTORIES=[${CMAKE_C_IMPLICIT_LINK_DIRECTORIES}]") +if("${last_dir}" IN_LIST CMAKE_C_IMPLICIT_LINK_DIRECTORIES) + message(FATAL_ERROR "${last_dir} was not excluded!") +endif() diff --git a/Tests/RunCMake/ParseImplicitLinkInfo/Inspect.cmake b/Tests/RunCMake/ParseImplicitLinkInfo/Inspect.cmake new file mode 100644 index 0000000..42e1c67 --- /dev/null +++ b/Tests/RunCMake/ParseImplicitLinkInfo/Inspect.cmake @@ -0,0 +1,12 @@ +enable_language(C) + +set(info "") +foreach(var + CMAKE_C_IMPLICIT_LINK_DIRECTORIES + ) + if(DEFINED ${var}) + string(APPEND info "set(INFO_${var} \"${${var}}\")\n") + endif() +endforeach() + +file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/info.cmake" "${info}") diff --git a/Tests/RunCMake/ParseImplicitLinkInfo/RunCMakeTest.cmake b/Tests/RunCMake/ParseImplicitLinkInfo/RunCMakeTest.cmake index 713e2e7..c7655d2 100644 --- a/Tests/RunCMake/ParseImplicitLinkInfo/RunCMakeTest.cmake +++ b/Tests/RunCMake/ParseImplicitLinkInfo/RunCMakeTest.cmake @@ -1,3 +1,11 @@ include(RunCMake) run_cmake(ParseImplicitLinkInfo) + +run_cmake(Inspect) +set(info "${RunCMake_BINARY_DIR}/Inspect-build/info.cmake") +include("${info}") + +if(INFO_CMAKE_C_IMPLICIT_LINK_DIRECTORIES MATCHES ";") + run_cmake_with_options(ExcludeDirs "-Dinfo=${RunCMake_BINARY_DIR}/Inspect-build/info.cmake") +endif() -- cgit v0.12