blt
blt copied to clipboard
Link options from MPI compiler wrapper collapsed incorrectly (CMake 3.13+)
CMake: 3.14.3 BLT: https://github.com/LLNL/blt/commit/938345715810c6457d3e57a2c20d4ee0fa253632
When using e.g. Intel MPI, link flags obtained from mpicc
may look like the following:
-Xlinker -rpath -Xlinker /path/to/A -Xlinker -rpath -Xlinker /path/to/B -Xlinker -rpath -Xlinker /path/to/C ...
After the link options are set on the target in blt_add_target_link_flags
via LINK_OPTIONS
, the resulting command line looks like:
-Xlinker -rpath /path/to/A /path/to/B /path/to/C ...
which is incorrect. This is because CMake removes duplicates, as per documentation.
Unless there is a way to pass the link flags verbatim (as opposed to splitting and adding one by one), perhaps the correct treatment would be:
- Collect and concatenate all consecutive options that have a preceding
-Xlinker
into a comma-separated string - Add the resulting string with a
LINKER:
prefix.
So we end up adding
LINKER:-rpath,/path/to/A,-rpath,/path/to/B,-rpath,/path/to/C
as a single link option, which CMake translates back into the correct string (using -Xlinker
or -Wl
syntax, as appropriate).
Solution that works for me (but is kinda ugly and very specific to just handling -Xlinker
flag): in blt_add_target_link_flags
if( ${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.13.0" )
# In CMake 3.13+, LINK_FLAGS was converted to LINK_OPTIONS.
# This now supports generator expressions but expects a list
# not a string
separate_arguments(_flag_list NATIVE_COMMAND "${arg_FLAGS}" )
set(_prev_xlinker 0)
set(_xlinker_flags "")
foreach( _flag ${_flag_list} )
# If previous flag was -Xlinker, accumulate current flag unto a list, reset the indicator
if(_prev_xlinker)
list(APPEND _xlinker_flags "${_flag}")
set(_prev_xlinker 0)
# Else, if current flag is -Xlinker, set the indicator
elseif("${_flag}" STREQUAL "-Xlinker")
set(_prev_xlinker 1)
# Else (a free-standing flag, i.e. a series of -Xlinker guarded flags is over),
# dump the accumulated list with a prefix, then add the current flag as well
else()
if(_xlinker_flags)
list(JOIN _xlinker_flags "," _xlinker_flags_str)
set_property(TARGET ${arg_TO} APPEND PROPERTY LINK_OPTIONS "LINKER:${_xlinker_flags_str}")
set(_xlinker_flags "")
endif()
set_property(TARGET ${arg_TO} APPEND PROPERTY LINK_OPTIONS "${_flag}")
endif()
endforeach()
# Once the list is done, also dump any accumulated -Xlinker guarded flags with a prefix
if(_xlinker_flags)
list(JOIN _xlinker_flags "," _xlinker_flags_str)
set_property(TARGET ${arg_TO} APPEND PROPERTY LINK_OPTIONS "LINKER:${_xlinker_flags_str}" )
set(_xlinker_flags "")
endif()
else()
...
endif()