【问题标题】:Copy out plain .o files with cmake使用 cmake 复制出普通的 .o 文件
【发布时间】:2018-08-23 14:38:00
【问题描述】:

我正在尝试让 cmake(在 linux 上)创建一些静态对象 (.o) 文件并将它们安装到外部目录。为此,我有一个列表object_sources,其中包含源的项目路径,并将其放在顶层CMakeLists.txt

set(local_objects "")
foreach(file ${object_sources})
    get_filename_component(cur ${file} NAME_WE)
    add_library("${cur}.o" OBJECT ${file})
    list(APPEND local_objects "${cur}.o")
# To confirm these variables are what I think they are:
    message("---> ${cur} | ${file}")
endforeach()

install(
# Also tried FILES, see below.
    TARGETS ${local_objects}
    CONFIGURATIONS Debug
# Also tried nothing instead of 'OBJECTS' (same outcome)
# and LIBRARY (cmake fails on error).
    OBJECTS
    DESTINATION "/some/external/dir"
)       

关于使用FILES,它无法工作,因为实际上从未创建过foo.o,所以我没有必要尝试获得正确的项目路径。

当我在 cmake 构建目录中找到实际的 make 命令时,它会在此过程中吐出 Built target foo.o 等。然而,如前所述,在任何地方都没有创建过foo.oinstall/some/external/dir 中创建了一个objects-Debug 目录,其中包含使用其名称(例如foo.o/)的每个目标的目录,并且在其中还有一些嵌套的目录底部的目录是我想要的对象,名称错误:foo.cpp.o

Cmake 可以随心所欲地构建它的构建树并命名它的临时对象,但我真的很想能够要求最终产品对象foo.o(不是foo.cpp.o)并以这种方式安装它.

这可能吗?我开始认为这完全违背了 cmake 的(隐式)目的,我应该将这些类型的任务单独保存在 shell 脚本或 makefile 中(其中任何一个都需要大约三行),并且只使用 cmake用于规范的库和可执行文件。

或者:如果我将每个对象创建为静态存档 (lib.a),我相信我可以让它工作,但这里的部分问题是需要修改其他东西的构建脚本,或者提取他们通过脚本(在这种情况下,我不妨在脚本中完成整个事情)。

【问题讨论】:

标签: build cmake


【解决方案1】:

我不知道在 CMake 中执行此操作的好方法,但可能最简单的方法是使用 OBJECT 库。这将允许您使用generator expressions 获取目标的目标文件,更具体地说是TARGET_OBJECTS 表达式。这是一个最小的示例,其中包含一个空 main 的单个 foo.c 文件:

cmake_minimum_required(VERSION 3.11)

project(foo C)

set(SOURCES foo.c)

add_library(foo_obj OBJECT ${SOURCES})

add_executable(foo $<TARGET_OBJECTS:foo_obj>)

set(OBJS $<TARGET_OBJECTS:foo_obj>)
message(STATUS "these are my objects: ${OBJS}") # generator expression printed here, not evaluated yet

add_custom_target(print_foo_objs
  COMMAND ${CMAKE_COMMAND} -E echo $<TARGET_OBJECTS:foo_obj>)

set(OBJ_ROOT_DIR $<TARGET_PROPERTY:foo,BINARY_DIR>) 

add_custom_target(copy_foo_objs
  COMMAND ${CMAKE_COMMAND} -E make_directory ${OBJ_ROOT_DIR}/myobjects/
  COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_OBJECTS:foo_obj> ${OBJ_ROOT_DIR}/myobjects/ 
  COMMAND_EXPAND_LISTS) # UPDATE

请注意,作为生成器表达式,您将无法在配置期间访问它(因此,message 将包含文本声明的生成器表达式),但只能在生成阶段访问。

如果您仍然需要重命名目标文件(即从 foo.c.ofoo.o),您可以调用自定义外部脚本来为您执行此操作。 此外,清理等方面可能存在问题,这将迫使您添加更多自定义目标和/或命令(以及相关的依赖项)来处理它。这种方法的另一个缺点。

更新COMMAND_EXPAND_LISTS 允许在生成器表达式中扩展列表,它是在 CMake 3.8 及更高版本中添加的(请参阅here)。

【讨论】:

  • 重命名不能用install(... RENAME ...)命令吗?
  • @AlexisWilke 这可能是真的,但它只在安装单个文件时才有效,对吗?
  • 我正在我的项目中尝试此解决方案,尽管我的对象库已创建并生成可执行文件并运行,但自定义目标(print_foo_objs、copy_foo_objs)不会被调用。
  • @jws 答案中提供的示例默认情况下不会调用它们,必须手动指定它们。否则,您可以设置适合您的依赖项或使用ALL 选项添加到默认构建目标(请参阅here
  • @Ragul 也许你过度使用了这个机制。仍然不确定我是否理解。您应该创建一个单独的问题并详细描述它。会有人回答的。评论部分有其局限性。
猜你喜欢
  • 1970-01-01
  • 2011-07-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-12
  • 1970-01-01
  • 2022-06-23
  • 2021-04-19
相关资源
最近更新 更多