使用cmake从复杂项目中仅安装一个目标(及其依赖项)(打开更好的解决方案)

时间:2013-06-18 09:01:20

标签: cmake ninja

假设我有一个由几个子项目A,B,C,D组成的项目...... 所有子项目都依赖于A ,这会相当频繁地更改。 另外,可能还有一些依赖项: 在此示例中, D取决于B

现在:很多人正在研究这些项目。主CMakeLists.txt文件应包含所有目录,以便构建all构建所有目录。但人们也希望能够只在其中一个项目上工作,而不必每次都构建/安装所有项目。

如果我正在使用D,我可以通过调用

轻松构建“仅”D
cmake --build . --target D -- -j7

ninja -j7 D

如果他们的某些东西发生了变化,这也将构建A和B.完美。

但是如何在不触发构建全部的情况下仅为D调用install? 如果我打电话,我希望如此:

ninja -j7 D install

它只构建了D(和依赖项),然后只安装了D 及其依赖项(A和B)。 相反,它构建目标all并安装所有。

我想保持目标所有人都在继续建设。所以EXCLUDE_FROM_ALL不是一个选项。但是朝着这个方向走,我找不到任何解决方案。

所以我在考虑以下策略:

  • 除子项目A外,所有其他目标设置为EXCLUDE_FROM_ALL,安装时可选。
  • 我添加了一个额外的子项目,它只依赖于所有其他子项目(也许我通过使用PARENT_SCOPE中设置的一些变量使每个目标发布其名称),人们将不得不在他们想要构建和安装所有内容时调用它

它会起作用吗?有没有更好的解决方案?

我们希望避免每个人都必须编辑主CMakeLists.txt文件以排除他不感兴趣的项目。解决方案应该可以移植到不同的操作系统。

修改

我尝试了我提出的策略,但它不起作用:在我的情况下,为目标设置一个install语句(即使指定为OPTIONAL)也会使EXCLUDE_FROM_ALL无效。在documentation中更好地阅读我发现:

Installing a target with EXCLUDE_FROM_ALL set to true has undefined behavior.

我也收到了这个警告:

Target <targetname> has EXCLUDE_FROM_ALL set and will not be built by default but an install rule has been provided for it.  CMake does not define behavior for this case.

编辑2:

我尝试将EXCLUDE_FROM_ALL作为add_subdirectory的选项(而不是add_library / add_executable),但是这些子目录中的所有安装语句似乎都被忽略:只安装非排除所有子目录中的安装语句

编辑3:

即使我激活CMAKE_SKIP_INSTALL_ALL_DEPENDENCY

set(CMAKE_SKIP_INSTALL_ALL_DEPENDENCY true)

在主CMakeLists.txt文件中,我省略了所有EXCLUDE_FROM_ALL,安装了我想要的多个目标可选(在我的情况下,除了A之外),如果在安装之前构建特定目标,那么命令:

ninja -j7 D && ninja install

由于某种原因会失败,说明C(其安装设置为OPTIONAL)不存在(它没有创建,因为D仅依赖于A和B)...

file INSTALL cannot find "<name of dll file for C>"

编辑4:

对我来说,它看起来像是一个cmake bug。 (我在Windows下使用2.8.11,也测试了2.8.10) 这个INSTALL命令

install(TARGETS ${targetname} RUNTIME DESTINATION . LIBRARY DESTINATION . OPTIONAL)

在cmake_install.cmake中转换为:

IF(NOT CMAKE_INSTALL_COMPONENT OR "${CMAKE_INSTALL_COMPONENT}" STREQUAL "Unspecified")   
     

FILE(INSTALL DESTINATION“$ {CMAKE_INSTALL_PREFIX} /。”TYPE SHARED_LIBRARY FILES * path_to_dll *)

     

IF(EXISTS“$ ENV {DESTDIR} $ {CMAKE_INSTALL_PREFIX} /./”而不是IS_SYMLINK“$ ENV {DESTDIR} $ {CMAKE_INSTALL_PREFIX} /./* dll_name *”)

IF(CMAKE_INSTALL_DO_STRIP)

  EXECUTE_PROCESS(COMMAND "C:/Programs/MinGW/bin/strip.exe" "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/./*dll_name*")

ENDIF(CMAKE_INSTALL_DO_STRIP)   ENDIF() ENDIF(NOT CMAKE_INSTALL_COMPONENT OR "${CMAKE_INSTALL_COMPONENT}" STREQUAL "Unspecified")

命令FILE缺少OPTIONAL!如果我手动添加OPTIONAL,它就可以了! (注意:我在这里编辑了* dll_name *和* path_to_dll *占位符)

编辑5:

我确认这是cmake的错误,或者至少是错误的文档。我会报告这个。 情况解决了要么更简单

install(TARGETS ${targetname} DESTINATION . OPTIONAL)

(但在我的情况下,这也将安装我不想要的.lib.a文件)

或在可选标志前面移动:

install(TARGETS ${targetname} OPTIONAL RUNTIME DESTINATION . LIBRARY DESTINATION .)

cmake documentation可以理解的是,OPTIONAL应该作为最后一个选项。

4 个答案:

答案 0 :(得分:12)

什么有效:

  • Remove dependency of "install" target to "all" target(曾在主CMakeLists.txt中):

    set(CMAKE_SKIP_INSTALL_ALL_DEPENDENCY true)

  • 设置为您不希望始终构建的所有目标的可选安装:

    install(TARGETS <<targetname>> DESTINATION . OPTIONAL)

  • 构建您要安装的目标

    ninja -j7 <<list of targets>>,或更一般地说:

    <<your builder>> <<your options>> <<list of targets>>

    这将构建列出及其依赖项

  • 的所有目标
  • 致电安装人员 ninja install。这将安装您构建的所有库,您明确提到的库以及它们所依赖的库。这解决了安装特定目标及其依赖项的问题!

  • 要在Unix和Windows上连接命令,您可以使用

    ninja -j7 <<list of targets>> && ninja install

  • 请注意,至少对于忍者而言,您不能简单地将“安装”添加到目标列表中,因为目标“安装”不再依赖于任何目标,并且并行化作业的忍者将运行安装你还在建立你的目标。替换旧的ninja -j7 install

    ninja -j7 && ninja install

    目标“all”仍然可用(它仍然是默认目标)。

  • 如果您需要创建要一起构建的目标列表,可以定义custom target

    add_custom_target(<<collective target name>> DEPENDS <<list of targets>>)

    这不会包含在目标中。添加一个COMMAND也可以为我们想要的目标创建一个安装目标,例如ninja -j7 install_D,但我认为现在我们超出了这个问题的范围。

进一步考虑:

  • (注意,2018年7月:这可能已经过时)如果您使用RUNTIME DESTINATION,LIBRARY DESTINATION等,很可能是因为CMake错误,OPTIONAL关键字应该准确放在下面指出的位置:

    install(TARGETS <<targetname>> OPTIONAL RUNTIME DESTINATION <<some dir>> LIBRARY DESTINATION <<some (other) dir>>)

    这与documentation中的内容相矛盾,我将继续向CMake开发人员报告此错误。

  • EXCLUDE_FROM_ALLINSTALL + OPTIONAL结合使用a bad idea

      

    将EXCLUDE_FROM_ALL设置为true的目标安装具有未定义的行为。

    (并且cmake会在解析代码时尝试警告您)

答案 1 :(得分:3)

如果您使用add_subdirectory将子项目添加到CMakeLists.txt,您将看到,在您的构建目录中,您拥有所有子项目的子目录。

如果您只想从D安装目标,请执行以下操作:

cd build-dir/D
make install

这只会安装D-target。

当然,您必须在build-dir之前构建项目。我正在使用这种方式使用gnu-make。我不知道它是否适用于忍者。

答案 2 :(得分:2)

当我回答here时, 最新版本的Ninja提供了仅在子目录中构建目标的选项。

同样的功能适用于安装。因此,如果您的问题中的目标 D 位于子目录 D 中,则可以运行此命令:

ninja D/install

在Nakeja Generator here的CMake文档中查找更多信息。

答案 3 :(得分:0)

如unapiedra所述,cmake生成的忍者构建文件包含rules,用于构建/测试/安装/打包特定目录中的内容。

这很好,但你不能这样做:

ninja <targetName>/install

你只能做

ninja path/where/targetName/is/install

如果您不知道 targetName 的位置,您可以使用:

ninja -t query <targetName>

查看输出。