From 1d7fddca8ea1f1ac243d824a3c61079c77be3a75 Mon Sep 17 00:00:00 2001 From: Brad King Date: Wed, 2 Jun 2021 10:11:13 -0400 Subject: CMakeParseImplicitLinkInfo: Honor GNU static runtime library flags With flags like `-static-libstdc++` or `-static-libgfortran`, the GNU compiler driver adds `-Bstatic ... -Bdynamic` around its language runtime library. Convert the libraries in between these to absolute paths so that mixed-language linking honors the static runtime libraries. --- Modules/CMakeParseImplicitLinkInfo.cmake | 32 ++++++++++++++++++++++ Tests/CMakeTests/ImplicitLinkInfoTest.cmake.in | 3 ++ .../linux-CXX-GNU-10.2.1-static-libstdc++.input | 1 + ...nux-Fortran-GNU-10.2.1-static-libgfortran.input | 1 + .../ParseImplicitLinkInfo.cmake | 2 +- .../linux-CXX-GNU-10.2.1-static-libstdc++.output | 2 +- ...ux-Fortran-GNU-10.2.1-static-libgfortran.output | 2 +- 7 files changed, 40 insertions(+), 3 deletions(-) diff --git a/Modules/CMakeParseImplicitLinkInfo.cmake b/Modules/CMakeParseImplicitLinkInfo.cmake index e848b55..a61f71b 100644 --- a/Modules/CMakeParseImplicitLinkInfo.cmake +++ b/Modules/CMakeParseImplicitLinkInfo.cmake @@ -72,6 +72,7 @@ function(CMAKE_PARSE_IMPLICIT_LINK_INFO text lib_var dir_var fwk_var log_var obj endif() endif() set(is_msvc 0) + set(search_static 0) if("${cmd}" MATCHES "${linker_regex}") string(APPEND log " link line: [${line}]\n") string(REGEX REPLACE ";-([LYz]);" ";-\\1" args "${args}") @@ -103,6 +104,10 @@ function(CMAKE_PARSE_IMPLICIT_LINK_INFO text lib_var dir_var fwk_var log_var obj elseif("${arg}" MATCHES "^-l([^:].*)$") # Unix library. set(lib "${CMAKE_MATCH_1}") + if(search_static AND lib MATCHES "^(gfortran|stdc\\+\\+)$") + # Search for the static library later, once all link dirs are known. + set(lib "SEARCH_STATIC:${lib}") + endif() list(APPEND implicit_libs_tmp ${lib}) string(APPEND log " arg [${arg}] ==> lib [${lib}]\n") elseif("${arg}" MATCHES "^(.:)?[/\\].*\\.a$") @@ -129,6 +134,12 @@ function(CMAKE_PARSE_IMPLICIT_LINK_INFO text lib_var dir_var fwk_var log_var obj string(REPLACE ":" ";" dirs "${dirs}") list(APPEND implicit_dirs_tmp ${dirs}) string(APPEND log " arg [${arg}] ==> dirs [${dirs}]\n") + elseif("${arg}" STREQUAL "-Bstatic") + set(search_static 1) + string(APPEND log " arg [${arg}] ==> search static\n" ) + elseif("${arg}" STREQUAL "-Bdynamic") + set(search_static 0) + string(APPEND log " arg [${arg}] ==> search dynamic\n" ) elseif("${arg}" MATCHES "^-l:") # HP named library. list(APPEND implicit_libs_tmp ${arg}) @@ -172,8 +183,29 @@ function(CMAKE_PARSE_IMPLICIT_LINK_INFO text lib_var dir_var fwk_var log_var obj # We remove items that are not language-specific. set(implicit_libs "") foreach(lib IN LISTS implicit_libs_tmp) + if("x${lib}" MATCHES "^xSEARCH_STATIC:(.*)") + set(search_static 1) + set(lib "${CMAKE_MATCH_1}") + else() + set(search_static 0) + endif() if("x${lib}" MATCHES "^x(crt.*\\.o|gcc_eh.*|.*libgcc_eh.*|System.*|.*libclang_rt.*|msvcrt.*|libvcruntime.*|libucrt.*|libcmt.*)$") string(APPEND log " remove lib [${lib}]\n") + elseif(search_static) + # This library appears after a -Bstatic flag. Due to ordering + # and filtering for mixed-language link lines, we do not preserve + # the -Bstatic flag itself. Instead, use an absolute path. + # Search using a temporary variable with a distinct name + # so that our test suite does not depend on disk content. + find_library("CMAKE_${lang}_IMPLICIT_LINK_LIBRARY_${lib}" NO_CACHE NAMES "lib${lib}.a" NO_DEFAULT_PATH PATHS ${implicit_dirs_tmp}) + set(_lib_static "${CMAKE_${lang}_IMPLICIT_LINK_LIBRARY_${lib}}") + if(_lib_static) + string(APPEND log " search lib [SEARCH_STATIC:${lib}] ==> [${_lib_static}]\n") + list(APPEND implicit_libs "${_lib_static}") + else() + string(APPEND log " search lib [SEARCH_STATIC:${lib}] ==> [${lib}]\n") + list(APPEND implicit_libs "${lib}") + endif() elseif(IS_ABSOLUTE "${lib}") get_filename_component(abs "${lib}" ABSOLUTE) if(NOT "x${lib}" STREQUAL "x${abs}") diff --git a/Tests/CMakeTests/ImplicitLinkInfoTest.cmake.in b/Tests/CMakeTests/ImplicitLinkInfoTest.cmake.in index 1254ff9..63c234a 100644 --- a/Tests/CMakeTests/ImplicitLinkInfoTest.cmake.in +++ b/Tests/CMakeTests/ImplicitLinkInfoTest.cmake.in @@ -2,6 +2,9 @@ # test it. include(${CMAKE_ROOT}/Modules/CMakeParseImplicitLinkInfo.cmake) +set(CMAKE_FIND_LIBRARY_PREFIXES "disabled-for-test-") +set(CMAKE_FIND_LIBRARY_SUFFIXES "-disabled-for-test") + #----------------------------------------------------------------------------- # Linux diff --git a/Tests/RunCMake/ParseImplicitData/linux-CXX-GNU-10.2.1-static-libstdc++.input b/Tests/RunCMake/ParseImplicitData/linux-CXX-GNU-10.2.1-static-libstdc++.input index 2582be8..387f149 100644 --- a/Tests/RunCMake/ParseImplicitData/linux-CXX-GNU-10.2.1-static-libstdc++.input +++ b/Tests/RunCMake/ParseImplicitData/linux-CXX-GNU-10.2.1-static-libstdc++.input @@ -11,6 +11,7 @@ CMAKE_CXX_COMPILER_RANLIB=/usr/bin/gcc-ranlib-10 CMAKE_CXX_COMPILER_TARGET= CMAKE_CXX_COMPILER_VERSION=10.2.1 CMAKE_CXX_COMPILER_VERSION_INTERAL= +CMAKE_CXX_IMPLICIT_LINK_LIBRARY_stdc++=/usr/lib/gcc/x86_64-linux-gnu/10/libstdc++.a Change Dir: /tmp/ii/CMakeFiles/CMakeTmp Run Build Command(s):/usr/bin/gmake -f Makefile cmTC_339dd/fast && /usr/bin/gmake -f CMakeFiles/cmTC_339dd.dir/build.make CMakeFiles/cmTC_339dd.dir/build diff --git a/Tests/RunCMake/ParseImplicitData/linux-Fortran-GNU-10.2.1-static-libgfortran.input b/Tests/RunCMake/ParseImplicitData/linux-Fortran-GNU-10.2.1-static-libgfortran.input index 8a801f7..16b38d2 100644 --- a/Tests/RunCMake/ParseImplicitData/linux-Fortran-GNU-10.2.1-static-libgfortran.input +++ b/Tests/RunCMake/ParseImplicitData/linux-Fortran-GNU-10.2.1-static-libgfortran.input @@ -11,6 +11,7 @@ CMAKE_Fortran_COMPILER_RANLIB=/usr/bin/gcc-ranlib-10 CMAKE_Fortran_COMPILER_TARGET= CMAKE_Fortran_COMPILER_VERSION=10.2.1 CMAKE_Fortran_COMPILER_VERSION_INTERAL= +CMAKE_Fortran_IMPLICIT_LINK_LIBRARY_gfortran=/usr/lib/gcc/x86_64-linux-gnu/10/libgfortran.a Change Dir: /tmp/ii/CMakeFiles/CMakeTmp Run Build Command(s):/usr/bin/gmake -f Makefile cmTC_07a63/fast && /usr/bin/gmake -f CMakeFiles/cmTC_07a63.dir/build.make CMakeFiles/cmTC_07a63.dir/build diff --git a/Tests/RunCMake/ParseImplicitLinkInfo/ParseImplicitLinkInfo.cmake b/Tests/RunCMake/ParseImplicitLinkInfo/ParseImplicitLinkInfo.cmake index 961a3f5..dcdc7f1 100644 --- a/Tests/RunCMake/ParseImplicitLinkInfo/ParseImplicitLinkInfo.cmake +++ b/Tests/RunCMake/ParseImplicitLinkInfo/ParseImplicitLinkInfo.cmake @@ -70,7 +70,7 @@ function(load_compiler_info infile lang_var outcmvars_var outstr_var) string(REGEX REPLACE "\r?\n" ";" in_lines "${in}") foreach(line IN LISTS in_lines) # check for special CMAKE variable lines and parse them if found - if("${line}" MATCHES "^CMAKE_([_A-Za-z0-9]+)=(.*)$") + if("${line}" MATCHES "^CMAKE_([_A-Za-z0-9+]+)=(.*)$") if("${CMAKE_MATCH_1}" STREQUAL "LANG") # handle CMAKE_LANG here set(lang "${CMAKE_MATCH_2}") else() diff --git a/Tests/RunCMake/ParseImplicitLinkInfo/results/linux-CXX-GNU-10.2.1-static-libstdc++.output b/Tests/RunCMake/ParseImplicitLinkInfo/results/linux-CXX-GNU-10.2.1-static-libstdc++.output index ac85fc7..d38dfee 100644 --- a/Tests/RunCMake/ParseImplicitLinkInfo/results/linux-CXX-GNU-10.2.1-static-libstdc++.output +++ b/Tests/RunCMake/ParseImplicitLinkInfo/results/linux-CXX-GNU-10.2.1-static-libstdc++.output @@ -1,3 +1,3 @@ -libs=stdc\+\+;m;gcc_s;gcc;c;gcc_s;gcc +libs=/usr/lib/gcc/x86_64-linux-gnu/10/libstdc\+\+.a;m;gcc_s;gcc;c;gcc_s;gcc dirs=/usr/lib/gcc/x86_64-linux-gnu/10;/usr/lib/x86_64-linux-gnu;/usr/lib;/lib/x86_64-linux-gnu;/lib library_arch=x86_64-linux-gnu diff --git a/Tests/RunCMake/ParseImplicitLinkInfo/results/linux-Fortran-GNU-10.2.1-static-libgfortran.output b/Tests/RunCMake/ParseImplicitLinkInfo/results/linux-Fortran-GNU-10.2.1-static-libgfortran.output index 6a594d3..edeb20c 100644 --- a/Tests/RunCMake/ParseImplicitLinkInfo/results/linux-Fortran-GNU-10.2.1-static-libgfortran.output +++ b/Tests/RunCMake/ParseImplicitLinkInfo/results/linux-Fortran-GNU-10.2.1-static-libgfortran.output @@ -1,3 +1,3 @@ -libs=gfortran;m;gcc_s;gcc;quadmath;m;gcc_s;gcc;c;gcc_s;gcc +libs=/usr/lib/gcc/x86_64-linux-gnu/10/libgfortran.a;m;gcc_s;gcc;quadmath;m;gcc_s;gcc;c;gcc_s;gcc dirs=/usr/lib/gcc/x86_64-linux-gnu/10;/usr/lib/x86_64-linux-gnu;/usr/lib;/lib/x86_64-linux-gnu;/lib library_arch=x86_64-linux-gnu -- cgit v0.12