问题 是否可以将安装后命令添加到cmake生成的顶级Makefile中?


cmake为安装规则生成如下内容:

# Special rule for the target install
install: preinstall
        @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Install the project..."
        /usr/local/bin/cmake -P cmake_install.cmake
.PHONY : install

我想要做的是在调用cmake_install.cmake后执行一些自定义命令,因此它看起来像:

# Special rule for the target install
install: preinstall
        @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Install the project..."
        /usr/local/bin/cmake -P cmake_install.cmake
        post_install_command_1
        ...
        post_install_command_n
.PHONY : install

对于我们编写的内容(6-10个要更新的宏),我可以使用“add_custom_command(TARGET ... POST_BUILD ...)”执行我想要的操作。但是,有很多第三方的东西安装完毕,我真的不想为所有这些东西添加POST_BUILD自定义命令(目前有19个项目有更多的东西,很难确定需要处理什么建成后而不是安装后)。我认为如果自定义命令仅在一个地方使用(即作为安装处理的最后一部分)并且我知道他们将完成所有必要的操作,那么维护会更容易。

是否有可能让cmake将命令添加到顶级Makefile的安装规则中?


4588
2018-04-03 17:53


起源



答案:


你可以使用 SCRIPT 要么 CODE 变种 安装 命令。如果将所需命令放在脚本中 PostInstall.cmake 在项目根目录中,将以下调用添加到最外层 CMakeLists.txt

install (SCRIPT "${CMAKE_SOURCE_DIR}/PostInstall.cmake")

install 命令被添加到 cmake_install.cmake 脚本按顺序,因此应该将调用添加到结尾 CMakeLists.txt 在所有其他安装完成后运行它。


8
2018-04-03 19:51



谢谢!我发誓,我尝试过类似的东西而且没有用。再次尝试它似乎工作。猜猜我必须有一个错字(或其他东西)让它无法工作。 - joast
这对我的子目录构建不起作用。在从子目录中包含所有cmake_install.cmake之前,执行最外层CMakeLists.txt的结尾。 - rickfoosusa
有点棘手,尤其是从根目录中指定子目录安装路径和目标,但最终使其工作。 - taranaki


答案:


你可以使用 SCRIPT 要么 CODE 变种 安装 命令。如果将所需命令放在脚本中 PostInstall.cmake 在项目根目录中,将以下调用添加到最外层 CMakeLists.txt

install (SCRIPT "${CMAKE_SOURCE_DIR}/PostInstall.cmake")

install 命令被添加到 cmake_install.cmake 脚本按顺序,因此应该将调用添加到结尾 CMakeLists.txt 在所有其他安装完成后运行它。


8
2018-04-03 19:51



谢谢!我发誓,我尝试过类似的东西而且没有用。再次尝试它似乎工作。猜猜我必须有一个错字(或其他东西)让它无法工作。 - joast
这对我的子目录构建不起作用。在从子目录中包含所有cmake_install.cmake之前,执行最外层CMakeLists.txt的结尾。 - rickfoosusa
有点棘手,尤其是从根目录中指定子目录安装路径和目标,但最终使其工作。 - taranaki


要添加安装后步骤,您需要在顶级CMakeLists.txt中添加目录。您必须在其中包含一个包含CMakeLists.txt的目录,以便设置安装后最后执行的安装后步骤。

第一步是添加安装后脚本使用的变量和值。构建期间可用的所有变量都不会在安装后可用,因此您必须在此处设置所需的所有内容。

在顶级CMakeLists.txt中,在执行了所有先前的add_subdirectory命令之后,添加类似这样的内容。

# Workaround for the lack of post_install steps.
# add_subdirectory is executed in order, this one must be last.
if(CMAKE_PROGRAM_PREFIX)
    # Make sure this is the LAST directory added.
    add_subdirectory(${CMAKE_SOURCE_DIR}/cmake/postinstall)
    # Add any variables you need during post install.
    install(CODE "set(CMAKE_PROGRAM_PREFIX \"${CMAKE_PROGRAM_PREFIX}\")")
    # Add any properties to your post install.
    get_property(PROGRAM_PREFIX_FILES GLOBAL PROPERTY PROGRAM_PREFIX_FILES)
    install(CODE "set(PROGRAM_PREFIX_FILES \"${PROGRAM_PREFIX_FILES}\")")
endif()

现在我们有变量,并且属性转换为可在安装后使用的变量。

接下来,我们需要在postinstall目录中有一个CMakeLists.txt文件。 Cmake将在构建结束时执行此文件。那时我们安装了一个SCRIPT,可以在安装后完成工作。

# CMake will execute this last in the build.
# Install the script that does the post install work.
install(SCRIPT "${CMAKE_SOURCE_DIR}/cmake/postinstall/ProgramPrefix.cmake")

现在我们将在ProgramPrefix.cmake中安装后获得控制权。 CMake将添加我们之前设置的变量。

# Make sure this was requested.
if(CMAKE_PROGRAM_PREFIX)
    # CMake builds a manifest of all files it has installed.
    foreach(file ${CMAKE_INSTALL_MANIFEST_FILES})
        # Make a list of installed files to compare.
        get_filename_component(nm ${file} NAME)
        list(APPEND fileindex ${nm})
    endforeach()

    # Process program prefix files.
    foreach(nm ${PROGRAM_PREFIX_FILES})
        list(FIND fileindex ${nm} efound)
        # Did we match a manifest file with our list of files?
        if(NOT efound LESS 0)
            # Process the file.
            program_prefix_file(${efound})
        endif()
    endforeach()
endif()

实际执行程序前缀还有一些工作要做,但是这个框架将允许您在安装完所有内容后执行cmake命令。


3
2018-04-30 23:16



我不明白有关程序前缀的东西。这有关系吗?或者只是一个随机代码示例,说明如何在安装后运行脚本? - Joakim
我想在一个支持autoconf和cmake构建的树中添加一个程序 - 前缀函数,如autoconf。程序前缀就是一个例子。 cmake post安装步骤可用于任何事情。 - rickfoosusa