CMake:如何链接库没有自动搜索功能FIND_PACKAGE?

Vin*_*ent 15 cmake

我想知道如何在没有任何FIND_PACKAGE的情况下查找/链接库.

假设我们有一个名为testlib的"个人"库:

/perso/testlib/include/testlib1.h
/perso/testlib/include/testlib2.h
/perso/testlib/lib/testlib1.a
/perso/testlib/lib/testlib2.a
Run Code Online (Sandbox Code Playgroud)

如何将其与CMake链接?

1)在CMakeLists.txt的代码中直接链接它的功能是什么?

2)如何让用户选择文件的位置?

3)我很难理解CMake解释什么和不解释什么.例如,如果您定义变量$ {MYVARIABLE_INCLUDE_DIR}或$ {MYVARIABLE_LIBRARIES}是"INCLUDE_DIR"或"LIBRARIES"由CMake解释的扩展名,或者如果我调用此变量$ {MYVARIABLE_INCDIR}没有区别?

4)如果在lib目录中有一个包含十个或更多库文件的库,如何执行相同的过程(包括"个人"库)?

5)最后,当你输入时TARGET_LINK_LIBRARIES(myexecutable gmp),你怎么知道这个库的名字是"gmp".为什么不"Gmp"或"GMP"?放入此函数的库的名称是否等于.a文件减去"lib"和".a"?比如libgmp.a - > gmp?如果我想链接一个名为libtestlolexample.a的库,我是否需要输入TARGET_LINK_LIBRARIES(myexecutable testlolexample)

非常感谢你.

tre*_*nki 15

您可以使用target_link_libraries(myexecutable mylib)链接到库"mylib".编译器将使用其默认方式来查找指定的库(例如,它将在Linux上查找libmylib.a).编译器只会查看link_directories(directory1 directory2 ...),因此您可以尝试使用该命令将所需目录添加到搜索路径中.

当"mylib"也用CMake编译时,这将被识别,一切都应该自动工作.

如果希望用户指定目录,可以使用缓存的CMake变量.set(MYPATH "NOT-DEFINED" CACHE PATH "docstring").

对于更复杂的东西,建议编写一个可以使用的CMake查找模块find_package.我建议你看看FindALSA.cmake哪个可以作为一个很好的起点.

有趣的部分是在最后:

if(ALSA_FOUND)
  set( ALSA_LIBRARIES ${ALSA_LIBRARY} )
  set( ALSA_INCLUDE_DIRS ${ALSA_INCLUDE_DIR} )
endif()

mark_as_advanced(ALSA_INCLUDE_DIR ALSA_LIBRARY)
Run Code Online (Sandbox Code Playgroud)

ALSA_LIBRARYALSA_INCLUDE_DIR变量是用户可配置的,并存储在缓存中,而ALSA_LIBRARIESALSA_INCLUDE_DIRS以及ALSA_FOUND得到计算,并是查找模块的用户应该使用的.

通常会使用find模块,如下所示:

find_package(ALSA REQUIRED)
include_directories(${ALSA_INCLUDE_DIRS})
target_link_libraries(myexe ${ALSA_LIBRARIES})
Run Code Online (Sandbox Code Playgroud)

我相信你可以适应你的个人图书馆.


Sam*_*eld 5

通常,当您想要链接到没有 find_package 模块的库(例如,它是一个不常见的库,或者它是您自己的库)时,您可以使用基本命令(find_X 命令)来设置变量与您的路径需要。include_directories然后您可以像 find_package ( , )一样使用这些变量target_link_libraries

如果您要从多个包中使用此库,您可能需要创建一个 find_package 模块;基本上它使用具有某些约定的相同命令。

其中任何一个都允许您指定要查找的路径(在 CMake 模块中),并且它们允许用户覆盖路径(变量显示为ccmake/中的选项cmake-gui)。

我很乐意添加其中一种或两种方法的示例,只需让我知道您在寻找什么即可。

如果你只是想要一个快速而肮脏的解决方案,你可以这样做,但我不推荐它:

include_directories(/perso/testlib/include)
add_executable(myexecutable myexecutable.cpp)
target_link_libraries(myexecutable
    /perso/testlib/lib/testlib1.a
    /perso/testlib/lib/testlib2.a)
Run Code Online (Sandbox Code Playgroud)

关于您关于target_link_libraries(#5)的问题,您可以通过多种方式实现。如果您愿意,您可以提供全名(例如target_link_libraries(myexe libfoo.a)),但我认为使用短名称(例如 )更好(我想更便携)target_link_libraries(myexe foo。您还可以包含链接器标志;我不确定我在哪里读到它,但我认为它可能会翻译不同链接器的 -L 和 -l 标志。

例如,如果我在同一目录中有一堆库,并且我知道名称,我可能会找到该目录,将其存储在变量中,然后执行以下操作:

# First, find and set TESTLIB_LIBRARY_DIR, e.g. with find_path
# ...

# This assumes the libraries are e.g. 'libtestlib1.a' and 'libtestlib2.a'
set(TESTLIB_LIBRARIES
    -L${TESTLIB_LIBRARY_DIR)
    -l testlib1
    -l testlib2)

add_executable(myexecutable myexecutable.cpp)
target_link_libraries(myexecutable ${TESTLIB_LIBRARIES})
Run Code Online (Sandbox Code Playgroud)

如果你想制作自己的 find_package 模块(就像 trenki 提到的那样,FindALSA.cmake似乎是一个很好的起点),你可以通过将目录添加到CMAKE_MODULE_PATH;来使用它。例如,如果您将模块放在子目录中cmake/modules/

# Look for extra CMake modules in a subdirectory of this project
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules/" ${CMAKE_MODULE_PATH})
Run Code Online (Sandbox Code Playgroud)

一个可能的问题是FindALSA.cmake:我不确定CMAKE_CURRENT_LIST_DIR是否可行。所以我认为你应该做出这个改变(我编写的模块中的第二项工作):

# Change this line
include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)

# To this (with no path/extension it will search the CMake modules path):
include(FindPackageHandleStandardArgs)
Run Code Online (Sandbox Code Playgroud)

要了解 的用法FIND_PACKAGE_HANDLE_STANDARD_ARGS,请查看FindPackageHandleStandardArgs.cmakeCMake Modules 目录。