CMake 自定义链接可执行命令,如何提取链接器选项?

ran*_*dom 4 linker cmake

我需要在我的 CMake 脚本中支持自定义可执行链接命令,即 Synopsys VCS。VCS 是 GCC 的包装器,但它使用特殊语法来传递 LD 选项:

vcs -LDFLAGS "<LINK_FLAGS>" <LINK_LIBRARIES> <OBJECTS>
Run Code Online (Sandbox Code Playgroud)

链接可执行文件的规则存在于CMAKE_CXX_LINK_EXECUTABLE变量中,所以我尝试使用它:

set(CMAKE_CXX_LINK_EXECUTABLE "echo CXXFLAGS: <CMAKE_CXX_LINK_FLAGS>  LINK_FLAGS: <LINKER_FLAGS> LINK_LIBRARIES: <LINK_LIBRARIES> OBJECTS: <OBJECTS> ")
Run Code Online (Sandbox Code Playgroud)

当我构建项目时,我得到:

CXXFLAGS: 
LINK_FLAGS:
LINK_LIBRARIES: -rdynamic ../slib/libslib.a ../dlib/libdlib.so -Wl,-rpath,/home/ripopov/proj_cmake/build/dlib 
OBJECTS: CMakeFiles/sim.dir/sc_main.cpp.o
Run Code Online (Sandbox Code Playgroud)

所以所有链接器标志和库都在 LINK_LIBRARIES

如何从中提取链接器标志LINK_LIBRARIES

Flo*_*ian 6

把我的评论变成答案

问题

我们来看看定义在 Linux/GNU/GCC/CXX 中的特定链接行CMAKE_CXX_LINK_EXECUTABLE

<CMAKE_CXX_COMPILER> <FLAGS> <CMAKE_CXX_LINK_FLAGS> <LINK_FLAGS> 
                     <OBJECTS> -o <TARGET> <LINK_LIBRARIES>
Run Code Online (Sandbox Code Playgroud)

由于您的问题在于LINK_LIBRARIES扩展规则,让我们仔细看看(以您的示例为例)其内容是如何在 中生成的cmLocalGenerator::OutputLinkLibraries()

LINK_LIBRARIES

但是您不希望这些链接器标志混入,LINK_LIBRARIES因为您的 Synopsys VCS GCC 包装器希望它们带有-LDFLAGS前缀/组。

你是对的,“库和标志不能相互分离。看起来生成的函数LINK_LIBRARIEScmLocalGenerator::OutputLinkLibraries。不幸的是,它将所有标志和库放入单个std::string.”

可能的解决方案

我看到五个选项(或它们的某种组合):

  1. 用 VCS 匹配前缀/替换普通的 gcc/ld 标志
  2. 解析-Wl,中间脚本中的链接器选项
  3. 不要使用扩展规则,而是使用 CMake 变量/生成器表达式
  4. 定义你自己的链接器语言
  5. 比动态链接库更喜欢静态库

所以 - 在选项 3 的变体中。 - 您需要知道为什么您看到的链接器选项在LINK_LIBRARIES那里,以及如何抑制然后在其他地方重新生成它们。

这是我成功测试的示例:

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)
Run Code Online (Sandbox Code Playgroud)

这会给

CXXFLAGS: 
LINK_FLAGS: -Wl,-rpath,[... my binary path ...]/lib
LINK_LIBRARIES: libslib.a lib/libdlib.so 
OBJECTS: CMakeFiles/main.dir/main.cpp.o
Run Code Online (Sandbox Code Playgroud)

主要问题是您是否真的需要-rdynamic-Wl,-rpath选项。

第一个可以跳过,见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")
Run Code Online (Sandbox Code Playgroud)

如果.so系统路径中有共享库,也可以跳过后者,例如Wikipediarpath

具体来说,它将共享库的路径编码到可执行文件(或另一个共享库)的头文件中。此 RPATH 标头值(在可执行和可链接格式标头标准中如此命名)可以覆盖或补充系统默认动态链接搜索路径。

参考