cmake 如何包含可通过多个链接库传递的目标包含目录

tvz2xvvm  于 2023-02-16  发布在  其他
关注(0)|答案(1)|浏览(144)

我们正在用C/C++编写一个嵌入式项目,目前出现了一些特殊的需求。2背景是有两个编译库定义了相同的符号。3编译器允许创建可重定位的输出模块(带有部分链接)并在链接时隐藏其他编译单元的符号。这也意味着输出模块不需要定义所有符号,这将在最终链接中完成。使用的编译器是TI LTS1.3.0。我将直接链接到手册的可重定位部分:https://software-dl.ti.com/codegen/docs/tiarmclang/rel1_3_0_LTS/compiler_manual/linker_description/04_linker_options/linker-output-options.html#stdz0756429
项目的另一部分几乎没有使用静态库在CMake上构建,这些静态库通过target_link_libraries相互链接。
为了让它工作,我为这两个输出模块中的每一个创建了一个“add_executable”-target。我通过CMake将静态库传递给它们,并使用target_link_libraries获得链接。但是现在我遇到了一个问题。静态库的所有内容都在这两个输出模块中编译。这是不希望的行为,因为正如前面所说,最终链接完成了链接缺失内容的工作-所以静态库也是如此。这也应该通过CMake用另一个add_executable命令来完成。
使用目标包含目录属性是不合适的,因为它只添加给定目标本身的包含目录,而不添加目标将包含并链接到的目标的包含目录。
例如,如果您有(伪代码):

#library A
function( create_libA )
  add_library( libA src/A.c )
  target_include_directories( libA PUBLIC /inc ) #contains A.h
endfunction()

#library B. different location
function( create_libB LIBA )
  add_library( libB src/B.c )
  target_link_libraries( libB PUBLIC ${LIBA} )
  target_include_directories( libB PUBLIC /inc ) #contains B.h
endfunction()

#target output module with partial linking. Only should link and compile LIBTOBELINKEDIN, not libB. different location.

function( build_part_module LIBB LIBTOBELINKEDIN )
  add_executable( outputModuleA src/func.c ) #func.c does include A.h
  #following would cause libA and libB also to be compiled and linked in the output due to transitive stuff as I understood, which is unwanted.
  target_link_libraries( outputModuleA PUBLIC ${LIBB} ${LIBTOBELINKEDIN} ) 
  #trying this
  get_target_property(libBInc ${LIBB} INTERFACE_INCLUDE_DIRECTORIES)
  #will only include B.h but not A.h. compilation will fail.
target_include_directories(outputModuleA /inc ${libBInc})

我没有在Cmake中找到任何解决这个问题的方法。这让我很困惑,因为当库传递transitive时,所有的include目录必须是已知的,这在文档中有说明。但是我知道只获取传递的lib的目标include目录并不包括其他的。
既然target_link_libraries也不能这样工作,我只能想到一个可能的递归解决方案,但对于这个我的知识是不存在的。
带有类似HEADERS_ONLY的target_link_libraries对这项工作很有帮助。
也可以说:如果输出模块包含了所有的定义,这就不是问题,因为链接器知道它们并会发挥它的魔力。因为我们使用生成的静态库将它们直接放置到RAM不同区域的节中。这意味着创建另一个链接器脚本用于部分链接,该链接器脚本定义了随后可以再次移动的节。但是我们越是朝着这个方向前进,我们就越不需要CMake。

wgeznvg7

wgeznvg71#

使用$<TARGET_PROPERTY>生成器表达式代替get_target_property:由表达式提取的属性值已经包括传递传播:

target_include_directories(outputModuleA PRIVATE
    $<TARGET_PROPERTY:libB,INTERFACE_INCLUDE_DIRECTORIES>
)

请注意,generator expressions的用途有限:并不是所有的函数都需要它们。target_include_directories的文档清楚地说明了该命令支持生成器表达式。

相关问题