【问题标题】:Unable to link the output (static library) of an external git CMake project to a CMake project无法将外部 git CMake 项目的输出(静态库)链接到 CMake 项目
【发布时间】:2015-03-27 05:47:37
【问题描述】:

我在尝试将最近推送到 Git 的库链接到我的 CMake 项目时遇到问题。

我已将库命名为 octal (GitHub) 并尝试将其链接到我的另一个库 bulletframe (GitHub)。这两个项目都是我创建的。

我预计第一次链接库不会起作用,所以我只从octal 中的几个源文件开始。 octal的文件夹结构如下:

.gitignore
CMakeLists.txt
.git/
build/ # generated project files go here, but right now it's empty
src/
    CMakeLists.txt
    octal.h # this is empty
    octal/
        vector/
            vector.h
            vector.cpp

八进制/CMakeLists.txt

#...

set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_HOME_DIRECTORY}")

add_subdirectory("src")

八进制/src/CMakeLists.txt

macro(add_include)
    set(ALL_INCLUDES ${ALL_INCLUDES} ${ARGV})
endmacro(add_include)

add_include("octal.h")
add_include("octal/vector/vector.cpp" "octal/vector/vector.h")

add_library(${PROJECT_NAME} STATIC ${ALL_INCLUDES})

install(TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_ARCHIVE_OUTPUT_DIRECTORY})

八进制/src/vector/vector.h

#pragma once

namespace octal
{
    class Vector
    {
        // ...
        Vector Add(Vector other);
        Vector Subtract(Vector other);
        Vector Multiply(Vector other);
        Vector Multiply(double x);
        Vector Divide(Vector other);
        Vector Divide(double x);
        // ...
    }
}

这些配置成功地构建了liboctal.a 文件,但是我不确定它们是否与bulletframe 正确链接。有多个文件使用来自octal 的类,但这是它在尝试编译第一个源文件entity.cpp 后给出的第一个错误:

fatal error: octal/vector/vector.h: No such file or directory
 #include "octal/vector/vector.h"
                                 ^
compilation terminated.
src\CMakeFiles\bulletframe.dir\build.make:57: recipe for target 'src/CMakeFiles/bulletframe.dir/entity.cpp.obj' failed
mingw32-make.exe[3]: *** [src/CMakeFiles/bulletframe.dir/entity.cpp.obj] Error 1
CMakeFiles\Makefile2:121: recipe for target 'src/CMakeFiles/bulletframe.dir/all' failed
mingw32-make.exe[2]: *** [src/CMakeFiles/bulletframe.dir/all] Error 2
CMakeFiles\Makefile2:133: recipe for target 'src/CMakeFiles/bulletframe.dir/rule' failed
mingw32-make.exe[1]: *** [src/CMakeFiles/bulletframe.dir/rule] Error 2
Makefile:130: recipe for target 'bulletframe' failed
mingw32-make.exe: *** [bulletframe] Error 2

bulletframe 的文件夹结构与octal 相似

bulletframe/CMakeLists.txt

include(ExternalProject)
set(EXPROJ_DIR    "${CMAKE_HOME_DIRECTORY}/external")
set(LIB_DIR       "${CMAKE_HOME_DIRECTORY}/lib")

set(OCTAL_NAME          "octal-git")
set(OCTAL_GIT           "https://github.com/TheOctopod/octal-cpp.git")
set(OCTAL_PREFIX        "${EXPROJ_DIR}/${OCTAL_NAME}")
set(OCTAL_SOURCE_DIR    "${EXPROJ_DIR}/${OCTAL_NAME}")
set(OCTAL_BUILD_DIR     "${EXPROJ_DIR}/${OCTAL_NAME}/build")
set(OCTAL_INSTALL_DIR   "${LIB_DIR}")

ExternalProject_Add(${OCTAL_NAME}
    PREFIX          ${OCTAL_PREFIX}
    TMP_DIR         ${OCTAL_PREFIX}-tmp
    STAMP_DIR       ${OCTAL_PREFIX}-stamp
    # - Download Step ------------------
    GIT_REPOSITORY  ${OCTAL_GIT}
    # - Update Step --------------------
    UPDATE_COMMAND  ""
    # - Configure Step -----------------
    SOURCE_DIR      ${OCTAL_SOURCE_DIR}
    # - Build Step ---------------------
    BINARY_DIR      ${OCTAL_BUILD_DIR}
    # - Install Step ------------------
    INSTALL_COMMAND ""
    CMAKE_ARGS
    "-DCMAKE_BUILD_TYPE=Release"
)

add_library("octal" STATIC IMPORTED)
set_target_properties("octal" PROPERTIES
    # this is where ExternalProject built liboctal.a at
    IMPORTED_LOCATION "${OCTAL_BUILD_DIR}/src"
)

add_subdirectory(src)

bulletframe/src/CMakeLists.txt

macro(add_include)
    set(ALL_INCLUDES ${ALL_INCLUDES} ${ARGV})
endmacro(add_include)

add_include("entity.cpp")

add_library(${PROJECT_NAME} STATIC ${ALL_INCLUDES})

target_link_libraries(${PROJECT_NAME} "octal")

就目前而言,我当前的配置无法使用Visual Studio 10 2013MinGW Makefiles 生成器构建bulletframe

当我目睹编译器每次都出现类似错误时,我想到了几个问题:

  • 我是否没有正确构建静态库 (octal)?
  • 我是否没有正确地将其链接到我的项目 (bulletframe)?

【问题讨论】:

    标签: c++ git linker cmake static-libraries


    【解决方案1】:

    看起来您正在构建八进制,但没有提供指向其源代码的正确路径(让 bulletframe 能够#include 它)也没有提供指向其编译库的正确路径。

    修复包含问题很简单;只需将路径添加到导入库的 INTERFACE_INCLUDE_DIRECTORIES 属性即可。但是,修复库的路径有点棘手。

    使用 MSVC,八进制库的完整路径将是

    ${OCTAL_SOURCE_DIR}/lib/<build type>/octal.lib
    

    其中&lt;build type&gt; 是“Debug”、“Release”等。但是,对于其他编译器,路径将是

    ${OCTAL_SOURCE_DIR}/lib/liboctal.a
    

    为了解决这个问题,我会这样做:

    add_library(octal STATIC IMPORTED)
    if(MSVC)
      set_target_properties(octal PROPERTIES
          IMPORTED_LOCATION_DEBUG "${OCTAL_SOURCE_DIR}/lib/Debug/octal.lib"
          IMPORTED_LOCATION_RELEASE "${OCTAL_SOURCE_DIR}/lib/Release/octal.lib"
          INTERFACE_INCLUDE_DIRECTORIES "${OCTAL_SOURCE_DIR}/src")
    else()
      set_target_properties(octal PROPERTIES
          IMPORTED_LOCATION "${OCTAL_SOURCE_DIR}/lib/liboctal.a"
          INTERFACE_INCLUDE_DIRECTORIES "${OCTAL_SOURCE_DIR}/src")
    endif()
    

    【讨论】:

    • 有趣的是你提到了 if 语句——实际上我只是为MSVC 添加了一个检查。但是,我感到困惑的一件事是为什么我需要定义octal 的源文件。拥有octal.libliboctal.a 还不够吗?如果我可以直接包含源代码,为什么还要编译一个库呢?无论如何,感谢您的回答,我稍后会尝试解决方案。
    • 您的解决方案奏效了——尽管我仍然希望能对上一条评论中提到的问题进行一些澄清。除非你想让我再提一个问题?
    • 我们真正想要公开的只是八进制的公共标头,而不是完整的源列表。参见例如this recent answer,它给出了我对如何构建库的源文件的看法。由于八进制的公共标头与源在同一路径中,我们只需要给出该路径。将八进制作为自包含库的一个主要优点是,即使它包含在多个目标中,也不需要多次编译。
    • 是因为链接库是IMPORTED,我需要像使用set_target_properties 那样明确定义包含目录,还是只是常见的做法?我不能说,octal.lib 中已经包含目录,因为target_include_directories 似乎暗示了您的链接答案?
    • 是的 - 这是因为它是进口的。 the docs 的第一段试图解释其中的原理。
    猜你喜欢
    • 2013-03-12
    • 1970-01-01
    • 1970-01-01
    • 2021-08-06
    • 1970-01-01
    • 2017-11-24
    • 2020-08-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多