如何让cmake在子文件夹中找到共享库

时间:2016-07-01 10:25:10

标签: c++ cmake shared-libraries

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

在我的图书馆项目中,我已将头文件放入名为" 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)

怎么回事?

1 个答案:

答案 0 :(得分:3)

我会首先处理您的实际问题并在此之后提供其他评论。从技术上讲,您要求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 article,也许还有this 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()命令将是你的朋友。

希望这能指明你正确的方向。