如何让cmake在子文件夹中找到共享库
How to make cmake find a shared library in a subfolder
我正在尝试学习如何制作共享库。并且以下似乎有效(如果您对此方法有任何反馈,请发表评论,我基本上不知道我在做什么)。
在我的库项目中,我将 header 文件放入名为 "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})
这是工作。问题是我想将 headers 和库都放入子文件夹中(具体来说:headers 为 /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)
怎么会?
我会先处理你的实际问题,然后再提供补充意见。从技术上讲,您要求 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_PATH and CMAKE_LIBRARY_PATH 来影响 CMake 在何处查找库。我希望以上任一选项都能使您的第二个案例奏效。
现在进行其他观察。您在每个 CMakeLists.txt
文件的第一行中请求了 非常 旧的最低 CMake 版本。您可能至少要考虑制作这个 2.8(个人而言,我建议更像是 3.2 或更高版本,但这取决于您的项目需要支持什么)。
您已使用文件 globbing 获取源列表和 headers。这是不稳健的,通常应该避免(参见对此 here). You will see plenty of example code use method this for simplicity, but it is not recommended for real world projects (the CMake documentation even says not to use it 的讨论)。如果您想要健壮的构建,请单独明确列出您的源文件和 header 文件。
如果您乐于要求 CMake 2.8.11 或更高版本(这些天您应该是),而不是调用 include_directories()
,这会让所有内容都选择您指定的 header 搜索路径,您应该更愿意将搜索路径要求附加到需要它的目标。您使用 target_include_directories()
执行此操作。上面的代码等效于:
target_include_directories(${PROJECT_NAME} PUBLIC include)
随着项目规模和复杂性的增加,这可以更好地控制 inter-target 依赖项。有关此主题的更多 in-depth 讨论,请参阅 this article and perhaps also this one(披露:这两篇文章都是我写的)。
您的库和程序是完全独立的源代码存储库吗?它们可以构建在同一个项目中吗?您可以在一个 CMakeLists.txt
文件中构建多个目标。项目名称不必与任何目标的名称有任何关系(您经常在简单示例中看到目标名称的 PROJECT_NAME
变量 re-used,这很不幸,因为它暗示了一个两者之间的关系,但对于除简单项目之外的所有项目,情况并非如此)。如果它们在同一个存储库中,将它们构建在一起将是一个更简单的构建,因为您不必为可执行文件安装库来找到它并 link 到它。
如果它们必须在单独的项目中构建,那么应用程序项目的类似以下内容应该可以让您关闭:
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})
额外加分,可以尝试通过检查公共路径前缀来确认header路径与库在同一区域,或者直接导出
通过假定目录结构从 MYCUSTOMLIB 路径中获取 MCL_HEADER_PATH。两种方法都有优点和缺点。如果您想探索后者,get_filename_component() 命令将是您的朋友。
希望这能为您指明正确的方向。
我正在尝试学习如何制作共享库。并且以下似乎有效(如果您对此方法有任何反馈,请发表评论,我基本上不知道我在做什么)。
在我的库项目中,我将 header 文件放入名为 "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})
这是工作。问题是我想将 headers 和库都放入子文件夹中(具体来说:headers 为 /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)
怎么会?
我会先处理你的实际问题,然后再提供补充意见。从技术上讲,您要求 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_PATH and CMAKE_LIBRARY_PATH 来影响 CMake 在何处查找库。我希望以上任一选项都能使您的第二个案例奏效。
现在进行其他观察。您在每个 CMakeLists.txt
文件的第一行中请求了 非常 旧的最低 CMake 版本。您可能至少要考虑制作这个 2.8(个人而言,我建议更像是 3.2 或更高版本,但这取决于您的项目需要支持什么)。
您已使用文件 globbing 获取源列表和 headers。这是不稳健的,通常应该避免(参见对此 here). You will see plenty of example code use method this for simplicity, but it is not recommended for real world projects (the CMake documentation even says not to use it 的讨论)。如果您想要健壮的构建,请单独明确列出您的源文件和 header 文件。
如果您乐于要求 CMake 2.8.11 或更高版本(这些天您应该是),而不是调用 include_directories()
,这会让所有内容都选择您指定的 header 搜索路径,您应该更愿意将搜索路径要求附加到需要它的目标。您使用 target_include_directories()
执行此操作。上面的代码等效于:
target_include_directories(${PROJECT_NAME} PUBLIC include)
随着项目规模和复杂性的增加,这可以更好地控制 inter-target 依赖项。有关此主题的更多 in-depth 讨论,请参阅 this article and perhaps also this one(披露:这两篇文章都是我写的)。
您的库和程序是完全独立的源代码存储库吗?它们可以构建在同一个项目中吗?您可以在一个 CMakeLists.txt
文件中构建多个目标。项目名称不必与任何目标的名称有任何关系(您经常在简单示例中看到目标名称的 PROJECT_NAME
变量 re-used,这很不幸,因为它暗示了一个两者之间的关系,但对于除简单项目之外的所有项目,情况并非如此)。如果它们在同一个存储库中,将它们构建在一起将是一个更简单的构建,因为您不必为可执行文件安装库来找到它并 link 到它。
如果它们必须在单独的项目中构建,那么应用程序项目的类似以下内容应该可以让您关闭:
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})
额外加分,可以尝试通过检查公共路径前缀来确认header路径与库在同一区域,或者直接导出 通过假定目录结构从 MYCUSTOMLIB 路径中获取 MCL_HEADER_PATH。两种方法都有优点和缺点。如果您想探索后者,get_filename_component() 命令将是您的朋友。
希望这能为您指明正确的方向。