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

时间:2011-08-08 15:25:00

标签: cmake

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

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

/perso/testlib/include/testlib1.h
/perso/testlib/include/testlib2.h
/perso/testlib/lib/testlib1.a
/perso/testlib/lib/testlib2.a

如何将其与CMake链接?

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

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

3)我很难理解CMake解释什么以及什么不是。例如,如果你定义一个变量$ {MYVARIABLE_INCLUDE_DIR}或$ {MYVARIABLE_LIBRARIES}是“INCLUDE_DIR”或“LIBRARIES”一个由CMake解释的扩展名,或者如果我调用这个变量$ {MYVARIABLE_INCDIR}没有区别?

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

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

非常感谢。

3 个答案:

答案 0 :(得分:15)

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

当使用CMake编译“mylib”时,这将被识别,一切都应该自动生效。

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

对于更复杂的东西,建议编写一个可以与find_package一起使用的CMake查找模块。我建议你看看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)

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})

我相信你可以为你的个人图书馆进行调整。

答案 1 :(得分:4)

通常当你想链接一个没有find_package模块的库时(例如它是一个不常见的库,或者它是你自己的库),那么你可以使用基本命令(find_X命令)来设置变量你需要的路径。然后您将这些变量用作find_package(include_directoriestarget_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)

关于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})

如果你想创建自己的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})

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)

要获得FIND_PACKAGE_HANDLE_STANDARD_ARGS的使用,请查看CMake Modules目录中的FindPackageHandleStandardArgs.cmake

答案 2 :(得分:0)

CMake有一个很好的documentation

  1. 通过将STATIC关键字传递给add_library
  2. 来存档静态链接(如果我理解你是正确的)
  3. 我建议不要这样做(我不是CMake专家),但听起来费用会很大。
  4. 没有区别,${MYVARIABLE_INCLUDE_DIR}只是一个变量名称,无论你想要什么。但我建议您遵循命名惯例。
  5. 一个库总是一个.lib / .a文件,所以只要使用add_library& target_link_libraries&安培; add_dependencies功能。
  6. 库名称始终是您传递给add_library的名称。然而,Gmp或gMP与CMake案例强度相同