如何使用cmake导出系统库?

时间:2011-08-13 02:08:56

标签: c cmake

如何导出cmake库所依赖的库,以便依赖于该库的可执行文件不必手动依赖该库的依赖项?

这有点拗口,所以这是一个例子:

虚拟(应用)---->取决于liba

liba ---->取决于libpng

编译虚拟生成错误:

-- Found LIBPNG
-- Found LIBA
-- Configuring done
-- Generating done
-- Build files have been written to: /home/doug/projects/dummy/build
Linking C executable dummy
../deps/liba/build/liba.a(a.c.o): In function `a_dummy':
/home/doug/projects/dummy/deps/liba/src/a.c:6: undefined reference to `png_sig_cmp'
collect2: ld returned 1 exit status
make[2]: *** [dummy] Error 1
make[1]: *** [CMakeFiles/dummy.dir/all] Error 2
make: *** [all] Error 2

可以通过将其添加到CMakeLists.txt中来修复它:

TARGET_LINK_LIBRARIES(虚拟png)

然而,dummy并不知道liba如何实现其api。在某些时候,可能会变成libjpg或其他东西,这将打破虚拟应用程序。

在从cmake邮件列表中获得一些帮助之后,我被引导到这个例子来导出东西: http://www.cmake.org/Wiki/CMake/Tutorials/How_to_create_a_ProjectConfig.cmake_file

但是,遵循这种方法让我陷入了这条路:

export(TARGETS $ {LIBPNG_LIBRARY} FILE“$ {PROJECT_BINARY_DIR} /ALibraryDepends.cmake”)

显然我在这里遗漏了一些东西;这个'export'命令看起来像是为了将子项目输出到高水平;即。 liba中的嵌套项目。

但是,这不是问题所在。

配置liba(或任何cmake库)时,我将始终生成一个不属于该项目的依赖项列表。

当我使用find_package()解析liba时,如何导出它们以便它们作为LIBA_LIBRARY的一部分出现?

使用静态库不是一个选项(链接到opengl的静态库?没有。)

3 个答案:

答案 0 :(得分:7)

鉴于你对arrowdodger关于恐惧的答案的评论 安装一些东西会搞砸我选择给你的系统 以答案形式出现的概念性评论 长度。

链接cmake项目通过查找的find_package工作 * Config.cmake和* -config.cmake文件。

Project A&#39的CMakeLists.txt:

#CMakeLists.txt
project(A)
install(FILES 
  ${CMAKE_CURRENT_SOURCE_DIR}/AConfig.cmake share/A/cmake
)

#AConfig.cmake
message("Yepp, you've found me.")

$ mkdir build
$ cd build
$ cmake -DCMAKE_INSTALL_PREFIX=/tmp/test-install ..
$ make install

Project B&#39的CMakeLists.txt:

project(B)
find_package(A)

然后

$ mkdir build
$ cd build
$ cmake -DCMAKE_INSTALL_PREFIX=/tmp/test-install ..
$ make install

结果

...
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
Yepp, you've found me.

B找到了A,因为它将AConfig.cmake安装到一个位置 cmake会在哪里找到它/分享/ A / cmake'和给予相同的 CMAKE_INSTALL_PREFIX的值。

现在就是这样。让我们考虑一下你可以做些什么 AConfig.cmake:AFAIK你想要的一切。但最常见的 任务是通过include()获取有关A目标的信息, 为第三方做一些额外的find_package调用 包(HINT HINT)并创建变量

A_LIBRARIES
A_INCLUDE_DIRS

您要包含的内容是由

创建的文件
install(EXPORT A-targets
   DESTINATION share/A/cmake
)

在A&#39的CMakeLists.txt中,其中A-targets是指全局cmake 在

中使用时累积所有目标信息的变量
install(TARGETS ...
  EXPORT A-targets
  ...
)

statments。 make install创建的内容是

/tmp/test-install/share/A/cmake/A-targets.cmake

然后与AConfig.cmake一起驻留在同一目录中。 请再看一下如何使用此文件的Wiki页面 在AConfig.cmake内。

关于export()命令:如果你的话,这很方便 项目已经变得巨大,需要相当多的时间 是时候安装它们了。为了加快速度,你想要使用什么 直接在A&#39的构建/目录中。它是一种优化,也是一种优化 在维基中解释。它仍然可以通过find_package()工作,参见

但我强烈建议您选择通常的make install 现在路线。

答案 1 :(得分:2)

我使用上面接受的解决方案找到了我自己的解决方案,我将其留给其他人使用:

在liba / CMakeLists.txt中:

# Self
set(A_INCLUDE_DIRS ${A_INCLUDE_DIRS} "${PROJECT_SOURCE_DIR}/include")
set(A_LIBRARIES ${A_LIBRARIES} "${PROJECT_BINARY_DIR}/liba.a")

# Libpng
FIND_PACKAGE(libpng REQUIRED)
set(A_INCLUDE_DIRS ${A_INCLUDE_DIRS} ${LIBPNG_INCLUDE_DIRS})
set(A_LIBRARIES ${A_LIBRARIES} ${LIBPNG_LIBRARIES})

ADD_LIBRARY(a ${SOURCES})

# Includes
INCLUDE_DIRECTORIES(${A_INCLUDE_DIRS})

# Allow other projects to use this
configure_file(AConfig.cmake.in "${PROJECT_BINARY_DIR}/AConfig.cmake")

在liba / AConfig.cmake中:

set(A_LIBRARIES @A_LIBRARIES@)
set(A_INCLUDE_DIRS @A_INCLUDE_DIRS@)

在dummy / CMakeLists.txt中:

FIND_PACKAGE(A REQUIRED)
INCLUDE_DIRECTORIES(${A_INCLUDE_DIRS})
TARGET_LINK_LIBRARIES(dummy ${A_LIBRARIES})

这会产生一个AConfig.cmake,其内容为:

set(A_LIBRARIES /home/doug/projects/dummy/deps/liba/build/liba.a;/usr/lib/libpng.so)
set(A_INCLUDE_DIRS /home/doug/projects/dummy/deps/liba/include;/usr/include)

详细的编译内容如下:

/usr/bin/gcc  -std=c99 -g   CMakeFiles/dummy.dir/src/main.c.o  -o dummy -rdynamic ../deps/liba/build/liba.a -lpng 

这正是我所寻找的。

答案 2 :(得分:1)

如果liba没有提供任何方法来确定它的依赖关系,那么你就无法做任何事情。 如果liba是由您开发的库并且您正在使用CMake构建它,那么您应该使用liba本身安装libaConfig.cmake文件,其中包含必要的定义。然后在dummy的CMakeLists.txt中包含libaConfig,以获取有关如何构建liba的信息。

您可以在LLVM项目中查看它是如何完成的,相关文件的扩展名为cmake.in http://llvm.org/viewvc/llvm-project/llvm/trunk/cmake/modules/

最后,在虚拟项目中你应该使用

target_link_libraries( ${LIBA_LIBRARIES} )

include_directories( ${LIBA_INCLUDE_DIR} )

link_directories( ${LIBA_LIBRARY_DIR} )

如果该liba仅由dummy使用,则可以从单个CMake项目构建它。这样更方便,因为每次重新编译时都不需要安装liba,每次运行make时都会自动重建和重新链接。 如果您喜欢这种方法,那么您应该做的唯一事情 - 使用PARENT_SCOPE选项在liba中定义CMakeLists.txt变量(参见set()命令手册)。

最后,你可以使用共享库,.so没有这样的问题。