【问题标题】:How to make cmake find a shared library in a subfolder如何让cmake在子文件夹中找到共享库
【发布时间】:2016-11-03 17:21:43
【问题描述】:

我正在尝试学习如何制作共享库。以下似乎有效(如果您对此方法有一些反馈,请发表评论,我基本上不知道我在做什么)。

在我的库项目中,我将头文件放入名为“include”的文件夹中,将源文件放入“src”中。

我的库的 CMakeLists.txt:

cmake_minimum_required(VERSION 2.4.0)

project(mycustomlib)

# Find source files
file(GLOB SOURCES src/*.cpp)

# Include header files
include_directories(include)

# Create shared library
add_library(${PROJECT_NAME} SHARED ${SOURCES})

# Install library
install(TARGETS ${PROJECT_NAME} DESTINATION lib)

# Install library headers
file(GLOB HEADERS include/*.h)
install(FILES ${HEADERS} DESTINATION include)

我的应用程序的 CMakeLists.txt:

cmake_minimum_required(VERSION 2.4.0)

project(myprogram)

# Find source files
file(GLOB SOURCES src/*.cpp)

# Create executable
add_executable(${PROJECT_NAME} ${SOURCES})

# Find and link library
find_library(MYCUSTOMLIB mycustomlib)
target_link_libraries(${PROJECT_NAME} ${MYCUSTOMLIB})

这是工作。问题是我想将标题和库都放入子文件夹(特别是:/usr/local/include/mycustomlib/ 用于标题,/usr/local/lib/mycustomlib/ 用于库)。

这是我的尝试:

我的库的新 CMakeLists.txt:

cmake_minimum_required(VERSION 2.4.0)

project(mycustomlib)

# Find source files
file(GLOB SOURCES src/*.cpp)

# Include header files
include_directories(include)

# Create shared library
add_library(${PROJECT_NAME} SHARED ${SOURCES})

# Install library
install(TARGETS ${PROJECT_NAME} DESTINATION lib/${PROJECT_NAME})

# Install library headers
file(GLOB HEADERS include/*.h)
install(FILES ${HEADERS} DESTINATION include/${PROJECT_NAME})

我的应用程序的新 CMakeLists.txt:

cmake_minimum_required(VERSION 2.4.0)

project(myprogram)

# Find source files
file(GLOB SOURCES src/*.cpp)

# Create executable
add_executable(${PROJECT_NAME} ${SOURCES})

# Find and link library
find_library(MYCUSTOMLIB mycustomlib/mycustomlib)
target_link_libraries(${PROJECT_NAME} ${MYCUSTOMLIB})

这是工作。现在,我不得不像这样指定库的 .so 文件:

find_library(MYCUSTOMLIB mycustomlib/libmycustomlib.so)

怎么会?

【问题讨论】:

    标签: c++ cmake shared-libraries


    【解决方案1】:

    我会先处理您的实际问题,然后再提供额外的 cmets。从技术上讲,您是在要求 CMake 查找名为 mycustomlib/mycustomlib 的库,但您真正想说的是您想要找到 mycustomlib,它可以在名为 mycustomlib 的子目录中找到。在第二种情况下,调用find_library() 以实现此目的的几种替代方法是:

    find_library(MYCUSTOMLIB mycustomlib PATH_SUFFIXES mycustomlib)
    find_library(MYCUSTOMLIB mycustomlib PATHS /usr/local/lib/mycustomlib)
    

    后者对库的安装位置做出了比应有的更多假设,所以我倾向于第一个选项。第一个选项假定 CMake 已经在 /usr/local/lib 中找到库,这似乎来自您的问题。您可以通过修改 CMAKE_PREFIX_PATHCMAKE_LIBRARY_PATH 来影响 CMake 查找库的位置。我希望上述任何一个选项都能使您的第二个案例发挥作用。

    现在进行其他观察。您在每个 CMakeLists.txt 文件的第一行中请求了一个非常旧的最低 CMake 版本。您可能至少要考虑制作这个 2.8(我个人建议更像 3.2 或更高版本,但这取决于您的项目需要支持什么)。

    您已使用文件通配符来获取源和标头列表。这并不可靠,通常应该避免(参见对此here 的讨论)。为简单起见,您将看到大量示例代码使用方法,但不建议将其用于实际项目(CMake 文档甚至 says not to use it)。如果您想要健壮的构建,请单独明确列出您的源文件和头文件。

    如果您愿意要求 CMake 2.8.11 或更高版本(现在您应该是),而不是调用 include_directories() 让所有内容都选择您指定的标头搜索路径,您应该更愿意附加搜索路径对需要它的目标的要求。您可以使用target_include_directories() 执行此操作。上面的代码相当于:

    target_include_directories(${PROJECT_NAME} PUBLIC include)
    

    随着项目规模和复杂性的增长,这可以更好地控制目标间的依赖关系。有关此主题的更深入讨论,请参阅 this articlethis one(披露:我写了两篇文章)。

    您的库和程序是完全独立的源代码存储库吗?它们可以在同一个项目中构建吗?您可以在一个CMakeLists.txt 文件中构建多个目标。项目名称不必与任何目标的名称有任何关系(在简单示例中,您经常看到 PROJECT_NAME 变量重新用于目标名称,这是不幸的,因为它暗示了两者之间的关系,但对于除简单项目之外的所有项目,情况并非如此)。如果它们在同一个存储库中,将它们构建在一起将是一个更简单的构建,因为您不必为可执行文件安装库来找到它并链接到它。

    如果它们必须在单独的项目中构建,那么应用程序项目的以下内容应该会让您接近:

    cmake_minimum_required(VERSION 2.8.11)
    project(myprogram)
    
    # List your program's sources here explicitly
    add_executable(myprogram src/foo.cpp src/bar.cpp)
    
    # Find and link library
    find_library(MYCUSTOMLIB mycustomlib PATH_SUFFIXES mycustomlib)
    target_link_libraries(myprogram PUBLIC ${MYCUSTOMLIB})
    
    # Find library's headers and add it as a search path.
    # Provide the name of one header file you know should
    # be present in mycustomlib's include dir.
    find_path(MCL_HEADER_PATH mycustomlib.h PATH_SUFFIXES mycustomlib)
    target_include_directories(myprogram PUBLIC ${MCL_HEADER_PATH})
    

    对于额外的点,您可以尝试通过检查公共路径前缀来确认标头路径与库位于同一区域,或者您可以直接派生 MYCUSTOMLIB 路径中的 MCL_HEADER_PATH 假设一个目录结构。两种方法都有优点和缺点。如果您想探索后者,get_filename_component() 命令将成为您的朋友。

    希望这会为您指明正确的方向。

    【讨论】:

    • 谢谢!如何包含标题子目录?
    • target_include_directories() 就是这样做的。在上面,我展示了在构建${PROJECT_NAME} 目标时如何将include 目录添加到标题搜索路径。如果您要添加的目录被指定为相对路径,CMake 文档实际上并没有说明它们与构建相关的内容(他们只提到了与安装相关的内容)。您可能需要进行实验以查看行为是什么。如果您没有得到预期的行为,请尝试 ${CMAKE_CURRENT_SOURCE_DIR}/include 而不是 include
    • 好的,我猜这个命令是为我的库的 CMakeLists.txt 准备的。但我仍然不明白如何在我的应用程序的 CMakeLists.txt 中指定库头子目录。
    • 答案已更新以演示将库的头目录添加到程序头搜索路径的一种方法。
    • 太棒了,谢谢!希望我能给超过 1 票。
    猜你喜欢
    • 1970-01-01
    • 2021-04-12
    • 2015-10-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-07
    • 2012-09-30
    • 2017-02-20
    相关资源
    最近更新 更多