【问题标题】:How to create a library with CMakeLists.txt and include it in another program?如何使用 CMakeLists.txt 创建库并将其包含在另一个程序中?
【发布时间】:2019-05-15 09:18:37
【问题描述】:

我是 C/C++ 开发新手,在 CLion IDE 中处理 CMakeLists.txt 时遇到了困难。

我无法创建可以在另一个程序中#include 的库(静态或共享)。

我有这种结构:

src/
 |
 |---> utilities/
 |         |---> CMakeLists.txt
 |         |---> utilties.h
 |         |
 |         |---> file_utilities/
 |         |            |---> file_utilities.h
 |         |            |---> file_utilities.c
 |        ...
 |
 |---> my_app
          |---> CMakeLists.txt
          |---> main.c

我已经生成了一个 libutilities.so 和一个 libutilities.a。在我的 main.c 文件中,如果我执行 #include "../utilities/utilities.h"#include "../utilities/file_utilities/file_utilities.h",它就可以工作。

更糟糕的是,如果我使用另一个程序创建另一个项目并链接我的 libutilities.so,链接似乎有效,但仍然无法包含我的标题。

我在 CMakeLists.txt 中尝试了许多配置、许多选项,但直到现在都没有成功。

这是我用于我的库的 CMakeLists.txt。我很确定问题出在这个文件中。

    cmake_minimum_required(VERSION 3.7)
    project(utilities VERSION 1.0.0)

    set(CMAKE_CXX_STANDARD 11)

    link_libraries(pthread)
    link_libraries(ssl)
    link_libraries(crypto)

    find_package(CURL REQUIRED)
    include_directories(${CURL_INCLUDE_DIRS})

    file(GLOB_RECURSE SOURCES RELATIVES "*.c")
    file(GLOB_RECURSE HEADERS RELATIVES "*.h")

    add_library(${PROJECT_NAME} SHARED ${SOURCES} ${HEADERS})

    set_target_properties(${PROJECT_NAME} PROPERTIES
            PUBLIC_HEADER "${HEADERS}"
            ARCHIVE_OUTPUT_DIRECTORY "lib"
            LIBRARY_OUTPUT_DIRECTORY "lib"
            OUTPUT_NAME ${PROJECT_NAME})

    target_include_directories(${PROJECT_NAME} PUBLIC .)

    target_link_libraries(${PROJECT_NAME} ${CURL_LIBRARIES})

    include(GNUInstallDirs)
    install(TARGETS ${PROJECT_NAME}
            LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
            ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
            PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME})

我想拥有更像#include <utilities/utilties.h> 的东西,因为它是一个库。但我不能让它工作。

在我提供的示例中,该库是一个简单的“utils”库,但我必须创建更多的东西,我必须交付并集成到我的另一个程序中。

【问题讨论】:

  • 最好为target_include_directories提供绝对路径。根据documentation,仅$<INSTALL_INTERFACE> 表达式允许相对路径。您没有显示 my_app/CMakeLists.txt 脚本。但假设它有target_link_libraries(<exe> utilities),事情应该可以工作。
  • 这更好,但它仍然无法按我的意愿工作。在当前项目中,我现在可以#include <utilities.h>,或者直接#include <file_utilities/file_utilities.h>。但是我仍然不能在我的 .so.a 库的另一个程序中使用它。我可以使用那些内置在 cmake-build-debug 文件夹中的吗?
  • 如果你想为其他项目提供头文件,通常的方法是安装那些头文件。然后,在另一个项目中,您只需将目录调整到该安装位置。您可能会发现 CMake packaging tutorial 对您的目的很有用。
  • 我只建议像现在一样使用add_library(utilities),然后在my_app/CMakeLists.txt 中添加add_subdirectory(utlities ${CMAKE_CURRENT_SOURCE_DIR}/../utilities) 和简单的target_link_libraries(my_app PUBLIC utilities)。不需要install(),它比简单的add_library() 更难维护。

标签: c cmake shared-libraries static-libraries


【解决方案1】:

我强烈建议阅读this article,其中创建了一个虚构的库目标,从项目结构到安装/导出。据我了解,作者的目标和你完全一样。当我开始时,这篇文章为我澄清了很多事情。我还推荐其中的项目结构。

项目结构:

libjsonutils
├── CMakeLists.txt
├── include
│   └── jsonutils
│       └── json_utils.h
├── src
│   ├── file_utils.h
│   └── json_utils.cpp
└── test
    ├── CMakeLists.txt
    └── src
        └── test_main.cpp

具体来说,您需要查看Targets and Properties,其中生成器表达式用于区分构建时和安装时的包含目录:

target_include_directories(JSONUtils
    PUBLIC 
        $<INSTALL_INTERFACE:include>    
        $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
    PRIVATE
        ${CMAKE_CURRENT_SOURCE_DIR}/src
)

稍后在This is how you do CMake 中解释了目标的安装过程和导出/导入。作者想要做的是能够在其他 cmake 项目中使用该库(例如,一个名为“example”的目标),只需执行以下操作:

find_package(JSONUtils 1.0 REQUIRED)
target_link_libraries(example JSONUtils::JSONUtils)

为了完成这项工作,您需要安装和导出库。作者鼓励这样安装:

include(GNUInstallDirs)
install(TARGETS JSONUtils
    EXPORT jsonutils-export
    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
    ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
)

还有这个用于导出:

install(EXPORT jsonutils-targets
  FILE
    JSONUtilsTargets.cmake
  NAMESPACE
    JSONUtils::
  DESTINATION
    ${CMAKE_INSTALL_LIBDIR}/cmake/JSONUtils
)

导出将在给定目标中放置一个名为 findJsonUtils.cmake 的文件。该文件将是您使用 find_package 机制在其他项目中导入库所需的文件。

本文中的所有代码示例均取自 Pablo Arias 的链接文章。

【讨论】:

  • 在 Stack Overflow 上,我们希望答案是有用的,即使不关注它的链接。但是您的回答目前有点没有链接。请至少将您提供的链接中的一些信息直接添加到问题帖子中。
【解决方案2】:

你的 CMakeLists.txt 在 inside utilities 尝试使用这个。

src/utilities/CMakeLists.txt:

target_include_directories(${PROJECT_NAME}
  PUBLIC
    $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/..>
)

对于应用程序,您应该具有以下内容: src/my_app/CMakeLists.txt:

target_link_libraries(${PROJECT_NAME} PRIVATE utilities)

你应该有简单的 src/CMakeLists.txt:

add_subdirectory(utilities)
add_subdirectory(my_app)

【讨论】:

    猜你喜欢
    • 2010-10-30
    • 1970-01-01
    • 1970-01-01
    • 2010-11-27
    • 2014-12-01
    • 1970-01-01
    • 2016-01-15
    • 2020-02-20
    • 2021-02-26
    相关资源
    最近更新 更多