我有以下情况:
这通常可以正常工作,但是用户的应用程序和预处理的链接器脚本(通过接口库)之间只有目标级别的依赖关系。没有文件级依赖关系,因此当我修改链接描述文件的源时,会重新生成预处理的链接描述文件,但不会重新链接用户的应用程序。
这是一个测试用例
$ ls
CMakeLists.txt dummy.c linker-script.ld-source main.c
$ cat CMakeLists.txt
cmake_minimum_required(VERSION 3.1)
project(a_test)
add_custom_command(OUTPUT linker-script.ld
COMMAND cmake -E copy ${CMAKE_CURRENT_SOURCE_DIR}/linker-script.ld-source linker-script.ld
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/linker-script.ld-source)
add_custom_target(linker-script DEPENDS linker-script.ld)
add_library(static-library STATIC
dummy.c)
add_library(interface-library INTERFACE)
target_link_libraries(interface-library INTERFACE
# -Tlinker-script.ld
static-library)
add_dependencies(interface-library linker-script)
add_executable(application
main.c)
target_link_libraries(application interface-library)
$ cat main.c
int main(void)
{
return 0;
}
dummy.c
和linker-script.ld-source
只是空的。实际上并未使用生成的链接描述文件,但推荐的片段显示了我打算如何使用它。让我们来运行它:
$ mkdir output
$ cd output
$ cmake ..
-- The C compiler identification is GNU 8.1.0
-- The CXX compiler identification is GNU 8.1.0
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /tmp/cmake/output
$ make
Scanning dependencies of target static-library
[ 20%] Building C object CMakeFiles/static-library.dir/dummy.c.o
[ 40%] Linking C static library libstatic-library.a
[ 40%] Built target static-library
Scanning dependencies of target linker-script
[ 60%] Generating linker-script.ld
[ 60%] Built target linker-script
Scanning dependencies of target application
[ 80%] Building C object CMakeFiles/application.dir/main.c.o
[100%] Linking C executable application
[100%] Built target application
好的,一切似乎都很好。现在让我们说链接器脚本的源代码已更新:
$ touch ../linker-script.ld-source
$ make
[ 40%] Built target static-library
[ 60%] Generating linker-script.ld
[ 60%] Built target linker-script
[100%] Built target application
如您所见,应用程序未重新链接,这是一个问题。有什么想法可以解决这种情况吗?
答案 0 :(得分:0)
(至少现在)唯一正确的解决方案是使用LINK_DEPENDS目标属性。为此,我添加了自己的帮助函数,如下所示:
#
# Specifies linker script(s) used for linking `target`.
#
# `distortosTargetLinkerScripts(target [linker-script.ld ...])`
#
# Most common use will be with single linker script provided by distortos:
# `distortosTargetLinkerScripts(target $ENV{DISTORTOS_LINKER_SCRIPT})`
#
# Proper linker flag is added, as well as CMake dependency via LINK_DEPENDS target property.
#
function(distortosTargetLinkerScripts target)
foreach(linkerScript IN LISTS ARGN)
target_link_libraries(${target} PRIVATE
-T"${linkerScript}")
get_target_property(linkDepends ${target} LINK_DEPENDS)
if(NOT linkDepends)
unset(linkDepends)
endif()
list(APPEND linkDepends "${linkerScript}")
set_target_properties(${target} PROPERTIES
LINK_DEPENDS "${linkDepends}")
endforeach()
endfunction()
答案 1 :(得分:0)
更新:通过为CMake 3.13(INTERFACE_LINK_DEPENDS
和LINK_DEPENDS
中提到忍者的更新文档)中的接口目标添加新的目标属性,似乎似乎有了更多的支持。作为受支持的生成器(尽管不确定在什么版本的CMake中实际实现该功能)。
注意:这不是一个完整的答案,只是记录了我使用忍者作为生成器的情况
使用LINK_DEPENDS
不适用于非Makefile
生成器,例如Ninja。
在this邮件列表帖子中找到的方法中,我通常的方法是使用虚拟文件并使用
修改其时间戳。add_custom_command(OUTPUT linker-script.ld
[...]
COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_CURRENT_SOURCE_DIR}/dummy.c
[...])
不过,这仍然无法正常工作,因为在第一次调用时,它会检测到链接描述文件已过时,从而执行其复制并“接触”虚拟源文件。但是,需要第二次调用才能进行修改并重建所有相关目标。
这很不方便,但是我相信这是Ninja对依赖项进行分类(隐式,显式,仅顺序)引起的。使用add_dependencies
命令只能创建仅订购的Ninja依赖项,因为链接程序脚本不会以CMake术语影响您要用来运行二进制目标的构建行。
对于interface库,我什至看不到它在这种情况下有什么帮助,因为它甚至没有创建构建输出。它主要像一个组织占位符。
答案 2 :(得分:0)
这是一篇可能有帮助的文章
请参阅此部分:
- 自定义目标的文件级相关性不会传播
简而言之,您还需要将链接程序脚本依赖项添加到库中。是的,这很糟糕。
add_dependencies(interface-library linker-script linker-script.ld-source)