CMake:从“make install [all]”中排除自定义安装目标

Posted

技术标签:

【中文标题】CMake:从“make install [all]”中排除自定义安装目标【英文标题】:CMake: Exclude custom install target(s) from 'make install [all]' 【发布时间】:2013-05-10 16:29:11 【问题描述】:

我有一个作为我的项目的一部分构建并链接到的库。我想提供设施,可以选择在系统范围内安装库(或设置 $CMAKE_INSTALL_PREFIX 的任何位置)。否则,默认情况下,项目的最终构建产品将静态链接到库,并安装前者,但库二进制文件保留在构建目录中。

换句话说:

$ make
$ make install

将构建和安装程序,但仅限于类似

$ make install.foo

将库安装到 $CMAKE_INSTALL_PREFIX,如果需要,首先构建它。

到目前为止我有这样的东西(从实际脚本中简化,所以可能会有错误):

INCLUDE_DIRECTORIES( "$CMAKE_CURRENT_LIST_DIR")
SET (FOO_LIBRARY "foo")

# Following builds library and makes it available to
# be linked other targets within project by:
# TARGET_LINK_LIBRARIES($progname $FOO_LIBRARY)
ADD_LIBRARY($FOO_LIBRARY
    foo/foo.cpp # and other sources ...
    )

###########################################################
# Approach #1
# -----------
# Optionally allow users to install it by invoking:
#
#       cmake .. -DINSTALL_FOO="yes"
#
# This works, but it means that users will have to run
# cmake again to switch back and forth between the libary
# installation and non-library installation.
#
OPTION(INSTALL_FOO "Install foo" OFF)
IF (INSTALL_FOO)
    INSTALL(TARGETS $FOO_LIBRARY DESTINATION lib/foo)
    SET(FOO_HEADERS foo/foo.h)
    INSTALL(FILES $FOO_HEADERS DESTINATION include/foo)
    UNSET(INSTALL_FOO CACHE)
ENDIF()
###########################################################

###########################################################
# Approach #2
# -----------
# Optionally allow users to install it by invoking:
#
#       make install.foo
#
# Unfortunately, this gets installed by "make install",
# which I want to avoid
SET(FOO_INSTALL "install.foo")
ADD_CUSTOM_TARGET($FOO_INSTALL
    COMMAND $CMAKE_COMMAND
        -D COMPONENT=foo
        -P cmake_install.cmake)
ADD_DEPENDENCIES($FOO_INSTALL $FOO_LIBRARY)
INSTALL(TARGETS $FOO_LIBRRARY
    DESTINATION lib/foo COMPONENT foo)
SET(FOO_HEADERS foo/foo.h)
INSTALL(FILES $FOO_HEADERS
    DESTINATION include/foo COMPONENT foo)
###########################################################

可以看出,方法#1 的工作,但安装库所需的步骤是:

$ cmake .. -DINSTALL_FOO="yes"
$ make && make install

然后,要返回“正常”构建,用户必须记住在没有“-DINSTALL_FOO”选项的情况下再次运行 cmake,否则该库将在下一次“make install”时安装。

第二种方法在我运行“make install.foo”时有效,但如果我运行“make install”,它也会安装库。我想避免后者。

有人对如何实现这一目标有任何建议吗?

【问题讨论】:

【参考方案1】:

您在方法 2 的正确轨道上。您可以使用install 命令的OPTIONAL 开关来诱使CMake 避免安装FOO 相关文件。

对于FOO库目标,命令必须按以下方式修改:

SET (FOO_LIBRARY "foo")
ADD_LIBRARY($FOO_LIBRARY EXCLUDE_FROM_ALL
    foo/foo.cpp 
    )
INSTALL(TARGETS $FOO_LIBRARY
    DESTINATION lib/foo COMPONENT foo OPTIONAL)

EXCLUDE_FROM_ALL 被添加到ADD_LIBRARY 以防止在您运行普通的make 时构建库。通过添加OPTIONAL 开关,FOO_LIBRARY 的安装是可选的。

安装FOO_HEADERS 可选需要以下更改:

SET(FOO_HEADERS foo/foo.h)
SET(BINARY_FOO_HEADERS "")
FOREACH (FOO_HEADER $FOO_HEADERS)
    ADD_CUSTOM_COMMAND(
        OUTPUT $CMAKE_CURRENT_BINARY_DIR/$FOO_HEADER
        COMMAND $CMAKE_COMMAND -E copy $CMAKE_CURRENT_SOURCE_DIR/$FOO_HEADER $CMAKE_CURRENT_BINARY_DIR/$FOO_HEADER
        DEPENDS $CMAKE_CURRENT_SOURCE_DIR/$FOO_HEADER)
    LIST (APPEND BINARY_FOO_HEADERS $CMAKE_CURRENT_BINARY_DIR/$FOO_HEADER)
ENDFOREACH()
INSTALL(FILES $BINARY_FOO_HEADERS
    DESTINATION include/foo COMPONENT foo OPTIONAL)

FOREACH 循环设置自定义命令,将FOO_HEADERS 逐字复制到相应的二进制目录。 INSTALL(FILES ... 命令不是直接使用当前源目录中的头文件,而是从二进制目录中提取复制的头文件。二进制目录中标头的路径收集在变量BINARY_FOO_HEADERS中。

最后FOO_INSTALL 目标必须按以下方式设置:

SET(FOO_INSTALL "install.foo")
ADD_CUSTOM_TARGET($FOO_INSTALL
    COMMAND $CMAKE_COMMAND
        -D COMPONENT=foo
        -P cmake_install.cmake
    DEPENDS $BINARY_FOO_HEADERS)
ADD_DEPENDENCIES($FOO_INSTALL $FOO_LIBRARY)

自定义 FOO_INSTALL 添加了对 BINARY_FOO_HEADERS 的依赖以触发头文件的复制。当您运行 make install.foo 时,对 FOO_LIBRARY 的目标级别依赖会触发库的构建。

然而,该解决方案有以下缺点:

    配置 CMake 时会发出警告 Target "foo" has EXCLUDE_FROM_ALL set and will not be built by default but an install rule has been provided for it. 但无论如何 CMake 都会做正确的事情。

    1234563 /li>

【讨论】:

谢谢@sakra。如果存在链接到它的 make 目标,这是否会导致 FOO_LIBRARY 默认在普通“make”上自动构建? 是的。使用TARGET_LINK_LIBRARIES 将导致构建 FOO_LIBRARY。 谢谢!最好抑制 (1) 的警告。 EXCLUDE_FROM_ALL 具有undefined behavior if combined with INSTALL,即使与 OPTIONAL 结合使用:警告是有充分理由的,但不能保证此解决方案的行为一致。【参考方案2】:

检查this solution 是否适合您。

您必须使用与您说要使用的命令不同的命令,但我认为它很好地解决了问题。

【讨论】:

以上是关于CMake:从“make install [all]”中排除自定义安装目标的主要内容,如果未能解决你的问题,请参考以下文章

如何从 cmake 中运行 cmake?

CMake 从入门到崩溃3

cmake从入门到放弃

使用 cmake 从命令行使用 /MT 标志编译

从源码安装cmake

需要一些帮助来创建一个 cmake 文件以使我的项目正常工作...从 cmake 转换