假设我有一个由几个子项目A,B,C,D组成的项目...... 所有子项目都依赖于A ,这会相当频繁地更改。 另外,可能还有一些依赖项: 在此示例中, D取决于B 。
现在:很多人正在研究这些项目。主CMakeLists.txt文件应包含所有目录,以便构建all构建所有目录。但人们也希望能够只在其中一个项目上工作,而不必每次都构建/安装所有项目。
如果我正在使用D,我可以通过调用
轻松构建“仅”Dcmake --build . --target D -- -j7
或
ninja -j7 D
如果他们的某些东西发生了变化,这也将构建A和B.完美。
但是如何在不触发构建全部的情况下仅为D调用install? 如果我打电话,我希望如此:
ninja -j7 D install
它只构建了D(和依赖项),然后只安装了D 及其依赖项(A和B)。 相反,它构建目标all并安装所有。
我想保持目标所有人都在继续建设。所以EXCLUDE_FROM_ALL不是一个选项。但是朝着这个方向走,我找不到任何解决方案。
所以我在考虑以下策略:
它会起作用吗?有没有更好的解决方案?
我们希望避免每个人都必须编辑主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应该作为最后一个选项。
答案 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_ALL
与INSTALL
+ 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>
查看输出。