diff options
author | Christian Pfeiffer <cpfeiffer@live.de> | 2017-12-15 19:05:02 (GMT) |
---|---|---|
committer | Christian Pfeiffer <cpfeiffer@live.de> | 2018-01-25 15:31:10 (GMT) |
commit | 8b79107add5f27e06559ea6566b2c950857eae1e (patch) | |
tree | 228242f380cf4ee8366457b950e971fa61fbcb40 /Modules | |
parent | 5c3c70201d225359e235e53132788e6f75c2661b (diff) | |
download | CMake-8b79107add5f27e06559ea6566b2c950857eae1e.zip CMake-8b79107add5f27e06559ea6566b2c950857eae1e.tar.gz CMake-8b79107add5f27e06559ea6566b2c950857eae1e.tar.bz2 |
FindMPI: Improve link information parsing
The parsing of link information coming from the compiler wrapper has been improved:
- Support MSVC /link argument separation properly and add support for potential VC++ link flags
- Rely on the global import/static/shared library suffixes instead of hardcoded special values.
This should improve compatibility with Cygwin and MinGW should any MPI implementation there need this behavior.
- Don't use ``find_library`` if the full path of a library is known anyways.
Diffstat (limited to 'Modules')
-rw-r--r-- | Modules/FindMPI.cmake | 118 |
1 files changed, 65 insertions, 53 deletions
diff --git a/Modules/FindMPI.cmake b/Modules/FindMPI.cmake index c5eabbb..bf839df 100644 --- a/Modules/FindMPI.cmake +++ b/Modules/FindMPI.cmake @@ -421,25 +421,40 @@ function (_MPI_interrogate_compiler lang) set(MPI_LINK_CMDLINE "${MPI_COMPILE_CMDLINE}") endif() - # At this point, we obtained some output from a compiler wrapper that works. - # We'll now try to parse it into variables with meaning to us. - if("${LANG}" STREQUAL "Fortran") - # Some MPICH-1 and MVAPICH-1 versions return a three command answer for Fortran, consisting - # out of a symlink command for mpif.h, the actual compiler command and a deletion of the - # created symlink. We need to detect that case, remember the include path and drop the - # symlink/deletion operation to obtain the link/compile lines we'd usually expect. - if("${MPI_COMPILE_CMDLINE}" MATCHES "^ln -s ([^\" ]+|\"[^\"]+\") mpif.h") - get_filename_component(MPI_INCLUDE_DIRS_WORK "${CMAKE_MATCH_1}" DIRECTORY) - string(REGEX REPLACE "^ln -s ([^\" ]+|\"[^\"]+\") mpif.h\n" "" MPI_COMPILE_CMDLINE "${MPI_COMPILE_CMDLINE}") - string(REGEX REPLACE "^ln -s ([^\" ]+|\"[^\"]+\") mpif.h\n" "" MPI_LINK_CMDLINE "${MPI_LINK_CMDLINE}") - string(REGEX REPLACE "\nrm -f mpif.h$" "" MPI_COMPILE_CMDLINE "${MPI_COMPILE_CMDLINE}") - string(REGEX REPLACE "\nrm -f mpif.h$" "" MPI_LINK_CMDLINE "${MPI_LINK_CMDLINE}") + # For MSVC and cl-compatible compilers, the keyword /link indicates a point after which + # everything following is passed to the linker. In this case, we drop all prior information + # from the link line and treat any unknown extra flags as linker flags. + set(_MPI_FILTERED_LINK_INFORMATION FALSE) + if(MSVC) + if(MPI_LINK_CMDLINE MATCHES " [/-]link ") + string(REGEX REPLACE ".+[/-]link +" "" MPI_LINK_CMDLINE "${MPI_LINK_CMDLINE}") + set(_MPI_FILTERED_LINK_INFORMATION TRUE) endif() + string(REGEX REPLACE " +[/-]link .+" "" MPI_COMPILE_CMDLINE "${MPI_COMPILE_CMDLINE}") endif() - # The Intel MPI wrapper on Linux will emit some objcopy commands after its compile command - # if -static_mpi was passed to the wrapper. To avoid spurious matches, we need to drop these lines. if(UNIX) + # At this point, we obtained some output from a compiler wrapper that works. + # We'll now try to parse it into variables with meaning to us. + if("${LANG}" STREQUAL "Fortran") + # If MPICH (and derivates) didn't recognize the Fortran compiler include flag during configuration, + # they'll return a set of three commands, consisting out of a symlink command for mpif.h, + # the actual compiler command and deletion of the created symlink. + # Especially with M(VA)PICH-1, this appears to happen erroneously, and therefore we should translate + # this output into an additional include directory and then drop it from the output. + if("${MPI_COMPILE_CMDLINE}" MATCHES "^ln -s ([^\" ]+|\"[^\"]+\") mpif.h") + get_filename_component(MPI_INCLUDE_DIRS_WORK "${CMAKE_MATCH_1}" DIRECTORY) + string(REGEX REPLACE "^ln -s ([^\" ]+|\"[^\"]+\") mpif.h\n" "" MPI_COMPILE_CMDLINE "${MPI_COMPILE_CMDLINE}") + string(REGEX REPLACE "^ln -s ([^\" ]+|\"[^\"]+\") mpif.h\n" "" MPI_LINK_CMDLINE "${MPI_LINK_CMDLINE}") + string(REGEX REPLACE "\nrm -f mpif.h$" "" MPI_COMPILE_CMDLINE "${MPI_COMPILE_CMDLINE}") + string(REGEX REPLACE "\nrm -f mpif.h$" "" MPI_LINK_CMDLINE "${MPI_LINK_CMDLINE}") + endif() + endif() + + # If Intel MPI was configured for static linkage with -static_mpi, the wrapper will by default strip + # debug information from resulting binaries (see I_MPI_DEBUG_INFO_STRIP). + # Since we cannot process this information into CMake logic, we need to discard the resulting objcopy + # commands from the output. string(REGEX REPLACE "(^|\n)objcopy[^\n]+(\n|$)" "" MPI_COMPILE_CMDLINE "${MPI_COMPILE_CMDLINE}") string(REGEX REPLACE "(^|\n)objcopy[^\n]+(\n|$)" "" MPI_LINK_CMDLINE "${MPI_LINK_CMDLINE}") endif() @@ -460,7 +475,7 @@ function (_MPI_interrogate_compiler lang) endforeach() # Same deal, with the definitions. We also treat arguments passed to the preprocessor directly. - string(REGEX MATCHALL "(^| )(-Wp,|-Xpreprocessor |)[-/]D([^\" ]+|\"[^\"]+\")" MPI_ALL_COMPILE_DEFINITIONS "${MPI_COMPILE_CMDLINE}") + string(REGEX MATCHALL "(^| )(-Wp,|-Xpreprocessor )?[-/]D([^\" ]+|\"[^\"]+\")" MPI_ALL_COMPILE_DEFINITIONS "${MPI_COMPILE_CMDLINE}") foreach(_MPI_COMPILE_DEFINITION IN LISTS MPI_ALL_COMPILE_DEFINITIONS) string(REGEX REPLACE "^ ?(-Wp,|-Xpreprocessor )?[-/]D" "" _MPI_COMPILE_DEFINITION "${_MPI_COMPILE_DEFINITION}") @@ -489,7 +504,7 @@ function (_MPI_interrogate_compiler lang) endforeach() # Extract linker paths from the link command line - string(REGEX MATCHALL "(^| )(-Wl,|-Xlinker |)(-L|[/-]LIBPATH:|[/-]libpath:)([^\" ]+|\"[^\"]+\")" MPI_ALL_LINK_PATHS "${MPI_LINK_CMDLINE}") + string(REGEX MATCHALL "(^| )(-Wl,|-Xlinker )?(-L|[/-]LIBPATH:|[/-]libpath:)([^\" ]+|\"[^\"]+\")" MPI_ALL_LINK_PATHS "${MPI_LINK_CMDLINE}") # If extracting failed to work, we'll try using -showme:libdirs. if (NOT MPI_ALL_LINK_PATHS) @@ -506,8 +521,14 @@ function (_MPI_interrogate_compiler lang) list(APPEND MPI_LINK_DIRECTORIES_WORK "${_MPI_LPATH}") endforeach() + if(NOT _MPI_FILTERED_LINK_INFORMATION) + set(_MPI_LINK_FLAG_REGEX "(-Wl,|-Xlinker )") + else() + set(_MPI_LINK_FLAG_REGEX "") + endif() + # Extract linker flags from the link command line - string(REGEX MATCHALL "(^| )(-Wl,|-Xlinker )([^\" ]+|\"[^\"]+\")" MPI_ALL_LINK_FLAGS "${MPI_LINK_CMDLINE}") + string(REGEX MATCHALL "(^| )${_MPI_LINK_FLAG_REGEX}([^\" ]+|\"[^\"]+\")" MPI_ALL_LINK_FLAGS "${MPI_LINK_CMDLINE}") foreach(_MPI_LINK_FLAG IN LISTS MPI_ALL_LINK_FLAGS) string(STRIP "${_MPI_LINK_FLAG}" _MPI_LINK_FLAG) @@ -521,8 +542,7 @@ function (_MPI_interrogate_compiler lang) endif() endforeach() - # Extract the set of libraries to link against from the link command - # line + # Extract the set of libraries to link against from the link command line string(REGEX MATCHALL "(^| )-l([^\" ]+|\"[^\"]+\")" MPI_LIBNAMES "${MPI_LINK_CMDLINE}") foreach(_MPI_LIB_NAME IN LISTS MPI_LIBNAMES) @@ -536,34 +556,31 @@ function (_MPI_interrogate_compiler lang) endif() endforeach() - if(WIN32) - # A compiler wrapper on Windows will just have the name of the - # library to link on its link line, potentially with a full path - string(REGEX MATCHALL "(^| )([^\" ]+\\.lib|\"[^\"]+\\.lib\")" MPI_LIBNAMES "${MPI_LINK_CMDLINE}") - foreach(_MPI_LIB_NAME IN LISTS MPI_LIBNAMES) - string(REGEX REPLACE "^ " "" _MPI_LIB_NAME "${_MPI_LIB_NAME}") - string(REPLACE "\"" "" _MPI_LIB_NAME "${_MPI_LIB_NAME}") - get_filename_component(_MPI_LIB_PATH "${_MPI_LIB_NAME}" DIRECTORY) - if(NOT "${_MPI_LIB_PATH}" STREQUAL "") - list(APPEND MPI_LIB_FULLPATHS_WORK "${_MPI_LIB_NAME}") - else() - list(APPEND MPI_LIB_NAMES_WORK "${_MPI_LIB_NAME}") - endif() - endforeach() + # Treat linker objects given by full path, for example static libraries, import libraries + # or shared libraries if there aren't any import libraries in use on the system. + # Note that we do not consider CMAKE_<TYPE>_LIBRARY_PREFIX intentionally here: The linker will for a given file + # decide how to link it based on file type, not based on a prefix like 'lib'. + set(_MPI_LIB_NAME_REGEX "[^\" ]+${CMAKE_STATIC_LIBRARY_SUFFIX}|\"[^\"]+${CMAKE_STATIC_LIBRARY_SUFFIX}\"") + if(DEFINED CMAKE_IMPORT_LIBRARY_SUFFIX) + if(NOT ("${CMAKE_IMPORT_LIBRARY_SUFFIX}" STREQUAL "${CMAKE_STATIC_LIBRARY_SUFFIX}")) + string(APPEND _MPI_LIB_NAME_REGEX "[^\" ]+${CMAKE_IMPORT_LIBRARY_SUFFIX}|\"[^\"]+${CMAKE_IMPORT_LIBRARY_SUFFIX}\"") + endif() else() - # On UNIX platforms, archive libraries can be given with full path. - string(REGEX MATCHALL "(^| )([^\" ]+\\.a|\"[^\"]+\\.a\")" MPI_LIBFULLPATHS "${MPI_LINK_CMDLINE}") - foreach(_MPI_LIB_NAME IN LISTS MPI_LIBFULLPATHS) - string(REGEX REPLACE "^ " "" _MPI_LIB_NAME "${_MPI_LIB_NAME}") - string(REPLACE "\"" "" _MPI_LIB_NAME "${_MPI_LIB_NAME}") - get_filename_component(_MPI_LIB_PATH "${_MPI_LIB_NAME}" DIRECTORY) - if(NOT "${_MPI_LIB_PATH}" STREQUAL "") - list(APPEND MPI_LIB_FULLPATHS_WORK "${_MPI_LIB_NAME}") - else() - list(APPEND MPI_LIB_NAMES_WORK "${_MPI_LIB_NAME}") - endif() - endforeach() + string(APPEND _MPI_LIB_NAME_REGEX "[^\" ]+${CMAKE_SHARED_LIBRARY_SUFFIX}|\"[^\"]+${CMAKE_SHARED_LIBRARY_SUFFIX}\"") endif() + string(REPLACE "." "\\." _MPI_LIB_NAME_REGEX "${_MPI_LIB_NAME_REGEX}") + + string(REGEX MATCHALL "(^| )(${_MPI_LIB_NAME_REGEX})" MPI_LIBNAMES "${MPI_LINK_CMDLINE}") + foreach(_MPI_LIB_NAME IN LISTS MPI_LIBNAMES) + string(REGEX REPLACE "^ " "" _MPI_LIB_NAME "${_MPI_LIB_NAME}") + string(REPLACE "\"" "" _MPI_LIB_NAME "${_MPI_LIB_NAME}") + get_filename_component(_MPI_LIB_PATH "${_MPI_LIB_NAME}" DIRECTORY) + if(NOT "${_MPI_LIB_PATH}" STREQUAL "") + list(APPEND MPI_LIB_FULLPATHS_WORK "${_MPI_LIB_NAME}") + else() + list(APPEND MPI_LIB_NAMES_WORK "${_MPI_LIB_NAME}") + endif() + endforeach() # An MPI compiler wrapper could have its MPI libraries in the implictly # linked directories of the compiler itself. @@ -589,16 +606,11 @@ function (_MPI_interrogate_compiler lang) unset(MPI_DIRECT_LIB_NAMES_WORK) foreach(_MPI_LIB_FULLPATH IN LISTS MPI_LIB_FULLPATHS_WORK) get_filename_component(_MPI_PLAIN_LIB_NAME "${_MPI_LIB_FULLPATH}" NAME_WE) - get_filename_component(_MPI_LIB_NAME "${_MPI_LIB_FULLPATH}" NAME) - get_filename_component(_MPI_LIB_PATH "${_MPI_LIB_FULLPATH}" DIRECTORY) list(APPEND MPI_DIRECT_LIB_NAMES_WORK "${_MPI_PLAIN_LIB_NAME}") - find_library(MPI_${_MPI_PLAIN_LIB_NAME}_LIBRARY - NAMES "${_MPI_LIB_NAME}" - HINTS ${_MPI_LIB_PATH} - DOC "Location of the ${_MPI_PLAIN_LIB_NAME} library for MPI" - ) + set(MPI_${_MPI_PLAIN_LIB_NAME}_LIBRARY "${_MPI_LIB_FULLPATH}" CACHE FILEPATH "Location of the ${_MPI_PLAIN_LIB_NAME} library for MPI") mark_as_advanced(MPI_${_MPI_PLAIN_LIB_NAME}_LIBRARY) endforeach() + # Directly linked objects should be linked first in case some generic linker flags are needed for them. if(MPI_DIRECT_LIB_NAMES_WORK) set(MPI_PLAIN_LIB_NAMES_WORK "${MPI_DIRECT_LIB_NAMES_WORK};${MPI_PLAIN_LIB_NAMES_WORK}") endif() |