Turning my comments into an answer
The Problem
Let's take a look at the Linux/GNU/GCC/CXX specific link line defined in CMAKE_CXX_LINK_EXECUTABLE
:
<CMAKE_CXX_COMPILER> <FLAGS> <CMAKE_CXX_LINK_FLAGS> <LINK_FLAGS>
<OBJECTS> -o <TARGET> <LINK_LIBRARIES>
Since you problem is with the LINK_LIBRARIES
expansion rule, let's take a closer look (taking your example) at how its content is generated in cmLocalGenerator::OutputLinkLibraries()
:

But you don't want those linker flags mixed into LINK_LIBRARIES
because your Synopsys VCS GCC wrapper wants them a with -LDFLAGS
prefix/group.
And you're right "that libraries and flags are not separable from each other. It looks like that function that generates LINK_LIBRARIES
is cmLocalGenerator::OutputLinkLibraries
. And unfortunately it puts all flags and libs into single std::string
."
Possible Solutions
I see five options (or some combination of them):
- Prefix/Replace the normal gcc/ld flags with their VCS match
- Parse for linker
-Wl,
options in an intermediate script
- Don't use Expansion Rules but CMake variables/generator expressions
- Define your own linker language
- Prefer static libraries over dynamically linked libraries
So - in an variant of option 3. - you need to know why the linker options you see in LINK_LIBRARIES
are there and how you can suppress and then regenerate them elsewhere.
Here is an example that I have successfully tested:
cmake_minimum_required(VERSION 2.8)
project(LinkerVCS CXX)
file(WRITE foo.h "void foo();\n")
file(WRITE foo.cpp "void foo() {};\n")
file(WRITE bar.h "void bar();\n")
file(WRITE bar.cpp "void bar() {};\n")
file(
WRITE main.cpp
"#include \"foo.h\"\n"
"#include \"bar.h\"\n"
"int main() { foo(); bar(); return 0; }\n"
)
set(CMAKE_CXX_USE_RESPONSE_FILE_FOR_OBJECTS 0)
set(CMAKE_CXX_USE_RESPONSE_FILE_FOR_LIBRARIES 0)
# remove the '-rdynamic'
set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "")
# define my own search path for shared libraries
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_SHARED_LIBRARY_RUNTIME_CXX_FLAG}${CMAKE_BINARY_DIR}/lib")
set(CMAKE_CXX_LINK_EXECUTABLE "echo CXXFLAGS: ${CMAKE_CXX_FLAGS} LINK_FLAGS: <LINK_FLAGS> LINK_LIBRARIES: <LINK_LIBRARIES> OBJECTS: <OBJECTS>")
add_library(slib STATIC foo.cpp)
add_library(dlib SHARED bar.cpp)
add_executable(main main.cpp)
target_link_libraries(main slib dlib)
# remove the CMake generated '-Wl,-rpath'
set_target_properties(main PROPERTIES SKIP_BUILD_RPATH 1)
This will give
CXXFLAGS:
LINK_FLAGS: -Wl,-rpath,[... my binary path ...]/lib
LINK_LIBRARIES: libslib.a lib/libdlib.so
OBJECTS: CMakeFiles/main.dir/main.cpp.o
The main question would be if you really need the -rdynamic
and -Wl,-rpath
options.
The first can be skipped, see Linux-GNU.cmake
:
# We pass this for historical reasons. Projects may have
# executables that use dlopen but do not set ENABLE_EXPORTS.
set(CMAKE_SHARED_LIBRARY_LINK_${lang}_FLAGS "-rdynamic")
The later can also be skipped if you have the .so
shared libraries in the system paths, see e.g. Wikipedia rpath
:
Specifically it encodes a path to shared libraries into the header of an executable (or another shared library). This RPATH header value (so named in the Executable and Linkable Format header standards) may either override or supplement the system default dynamic linking search paths.
References