使用CMake安装ExternalProject

9

我在一个CMakeLists.txt文件中有以下代码:

FIND_PACKAGE(sphinxbase)
if (${SPHINXBASE_FOUND})
    INCLUDE_DIRECTORIES(${SPHINXBASE_INCLUDE_DIR}/sphinxbase/)
else ()
    ExternalProject_Add(
        sphinxbase
        GIT_REPOSITORY      "https://github.com/cmusphinx/sphinxbase.git"
        GIT_TAG             "e34b1c632392276101ed16e8a05862e43f038a7c"
        SOURCE_DIR          ${CMAKE_CURRENT_SOURCE_DIR}/lib/sphinxbase
        CONFIGURE_COMMAND   ${CMAKE_CURRENT_SOURCE_DIR}/lib/sphinxbase/autogen.sh
        BUILD_COMMAND       ${MAKE}
        UPDATE_COMMAND      ""
        INSTALL_COMMAND     ""
        BUILD_IN_SOURCE     ON
        LOG_DOWNLOAD        ON
        LOG_UPDATE          ON
        LOG_CONFIGURE       ON
        LOG_BUILD           ON
        LOG_TEST            ON
        LOG_INSTALL         ON
    )
    ExternalProject_Get_Property(sphinxbase SOURCE_DIR)
    ExternalProject_Get_Property(sphinxbase BINARY_DIR)
    SET(SPHINXBASE_SOURCE_DIR ${SOURCE_DIR})
    SET(SPHINXBASE_BINARY_DIR ${BINARY_DIR})
    SET(SPHINXBASE_LIBRARIES ${SPHINXBASE_BINARY_DIR}/src/libsphinxbase/.libs/libsphinxbase.a)
    INCLUDE_DIRECTORIES(${SPHINXBASE_SOURCE_DIR}/include)
endif ()
SET(DEPENDENCIES ${DEPENDENCIES} sphinxbase)
SET(LIBS ${LIBS} ${SPHINXBASE_LIBRARIES})

除了我正在尝试安装的目标之外,我该如何安装这个 ExternalProject?现在我正尝试按照以下方式进行:

install(TARGETS ${LIBS}
        LIBRARY DESTINATION lib
        ARCHIVE DESTINATION lib
        OPTIONAL
        )

install(TARGETS ${PROJECT_NAME}
        RUNTIME DESTINATION bin
        )

但我遇到了以下错误:
CMake Error at CMakeLists.txt:197 (install):
  install TARGETS given target
  "/Users/syb0rg/Dropbox/Development/Khronos/Khronos/lib/sphinxbase/src/libsphinxbase/.libs/libsphinxbase.a"
  which does not exist in this directory.
有什么建议吗?
1个回答

7

命令流 install(TARGETS) 安装由 add_executableadd_library 命令创建的目标文件。如果要安装具体的文件,则需要使用命令流 install(FILES)

除了从子项目的构建目录中安装选定的文件外,您还可以将子项目按原样安装。为此,您可以使用

make DESTDIR=<...> install

ExeternalProject_Add选项的命令设置为INSTALL。该命令将整个子项目安装到作为DESTDIR参数传递给make的目录中(有关此参数的更多信息可以在此处找到)。

然后,您可以使用install(DIRECTORY)命令一次性安装所有子项目文件:

# It is better to use binary directory for download or build 3d-party project 
set(sphinxbase_SOURCE_DIR ${CMAKE_CURRENT_BINARY_DIR}/lib/sphinxbase)
# This will be used as DESTDIR on subproject's `make install`.
set(sphinxbase_DESTDIR ${CMAKE_CURRENT_BINARY_DIR}/lib/sphinxbase_install)

ExternalProject_Add(
    sphinxbase
    GIT_REPOSITORY      "https://github.com/cmusphinx/sphinxbase.git"
    GIT_TAG             "e34b1c632392276101ed16e8a05862e43f038a7c"
    SOURCE_DIR          ${sphinxbase_SOURCE_DIR}
    # Specify installation prefix for configure.sh (autogen.sh).
    CONFIGURE_COMMAND   ./autogen.sh --prefix=${CMAKE_INSTALL_PREFIX}
    BUILD_COMMAND       ${MAKE}
    UPDATE_COMMAND      ""
    # Fake installation: copy installed files into DESTDIR.
    INSTALL_COMMAND     make DESTDIR=${sphinxbase_DESTDIR} install
    ...
)
# Actually install subproject.
install(
    DIRECTORY ${sphinxbase_DESTDIR}/
    DESTINATION "/"
    USE_SOURCE_PERMISSIONS # Remain permissions (rwx) for installed files
)

请注意,根目录被用作 DESTINATION。这是因为位于 sphinxbase_DESTDIR 目录下的文件已按照传递给 configure.sh(在此示例中为 autogen.sh)的 --prefix 选项的值 CMAKE_INSTALL_PREFIX 进行了定位。
如果您知道子项目仅在安装前缀下(由 --prefix 给出)安装其文件,则可以使主项目安装更加符合打包友好的要求。
install(
    DIRECTORY ${sphinxbase_DESTDIR}/${CMAKE_INSTALL_PREFIX}/
    DESTINATION "."
    USE_SOURCE_PERMISSIONS
)

因为现在DESTINATION选项使用的是相对路径,所以该项目将正确支持打包。例如,make DESTDIR=<...> install也适用于主要项目。
请注意,即使ExternalProject_Add用于构建CMake子项目,该子项目创建的目标也不会被主项目看到。

在使用./autogen.sh --prefix=${sphinxbase_DESTDIR}/${CMAKE_INSTALL_PREFIX}而不覆盖INSTALL_COMMAND的情况下,CMAKE_INSTALL_PREFIX + DESTDIR之间有什么区别?对于这种情况,DESTDIR相对于配置前缀是不方便的。 - HunterZ
1
@HunterZ:在自动化工具中,--prefix 不仅仅是指在 make install 时需要复制所有必要文件的目录:1. 对于类似于 //usr/local/opt 的系统范围前缀,某些文件可能会被安装 在前缀外。2. 它可以是存储在一个项目文件中的绝对路径,用于引用其他项目文件。因为(2),最好不要使用“虚假”的 --prefix - 它会使项目混乱。相反,DESTDIR 从未在项目文件中使用,并且保证所有项目文件将被安装在给定目录下。 - Tsyvarev
1
更准确地说,这是GNU Make特定的方法,支持DESTDIR=...语义。或者甚至是自动工具特定的方法。可能一些在Windows上工作的CMake生成器也有类似的语义。但是,“Linux方式”,“Windows方式”甚至“跨平台方式”……我非常不确定它们是否存在。“我可以理解为什么你给出了一个Linux答案,因为OP显然正在使用.a文件”——不是因为.a而是因为autogen.sh用于配置项目。据我所知,它是自动工具的一部分,只能在Linux上工作。 - Tsyvarev
非常有用的答案!不要忘记添加install(DIRECTORY ... USE_SOURCE_PERMISSIONS ...)以保留该目录中二进制文件的可执行权限(如果您构建了二进制文件)。 - xealits
@xealits:感谢您的评论,我已经在install(DIRECTORY)调用中添加了USE_SOURCE_PERMISSIONS。 - Tsyvarev
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接