【问题标题】:How do you export a system library using cmake?如何使用 cmake 导出系统库?
【发布时间】:2011-10-26 06:15:13
【问题描述】:

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

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

dummy(应用程序)----> 依赖于 liba

liba ----> 依赖于 libpng

编译 dummy 会产生错误:

-- 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 for dummy 来解决这个问题:

TARGET_LINK_LIBRARIES(虚拟 png)

但是,dummy 不知道 liba 如何实现其 api。在某些时候可能会变为 libjpg 或其他内容,这将破坏虚拟应用程序。

在从 cmake 邮件列表获得一些帮助后,我被引导到这个示例以导出内容: http://www.cmake.org/Wiki/CMake/Tutorials/How_to_create_a_ProjectConfig.cmake_file

但是,遵循这种方法让我陷入了困境:

导出(目标 ${LIBPNG_LIBRARY} 文件“${PROJECT_BINARY_DIR}/ALibraryDepends.cmake”)

显然我在这里遗漏了一些东西;这个“导出”命令看起来像是设计用于将子项目导出到高级; IE。 liba 中的嵌套项目。

但是,这不是这里的问题。

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

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

使用静态库不是一种选择(静态库用于链接到 opengl 的东西?不。)

【问题讨论】:

标签: c cmake


【解决方案1】:

鉴于您对arrowdodger关于恐惧的回答的评论 安装一些东西会弄乱你的系统我选择给 答案形式的概念性评论,因为它 长度。

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

项目 A 的 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

项目 B 的 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 会在哪里找到它 'share/A/cmake' 并得到相同的 CMAKE_INSTALL_PREFIX 的值。

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

A_LIBRARIES
A_INCLUDE_DIRS

您要包含的是由以下人员创建的文件

install(EXPORT A-targets
   DESTINATION share/A/cmake
)

在 A 的 CMakeLists.txt 中,其中 A-targets 指的是全局 cmake 使用时累积所有目标信息的变量

install(TARGETS ...
  EXPORT A-targets
  ...
)

声明。在 make install 中创建的是

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

然后与 AConfig.cmake 一起驻留在同一目录中。 请再次查看有关如何使用此文件的 wiki 页面 在 AConfig.cmake 中。

关于 export() 命令:如果你的 项目已经变得庞大,需要大量的 是时候安装它们了。为了加快速度,你想使用什么 直接在 A 的 build/ 目录下。这是一个优化,也是 在 wiki 中解释。它仍然可以通过 find_package() 工作,请参阅

但我强烈建议您进行通常的 make install 暂时的路线。

【讨论】:

    【解决方案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 
    

    这正是我想要的。

    【讨论】:

      【解决方案3】:

      如果 liba 没有提供任何方法来确定它的依赖关系,那么您将无能为力。 如果 liba 是您开发的库并且您正在使用 CMake 构建它,那么您应该使用 liba 本身安装 libaConfig.cmake 文件,该文件将包含必要的定义。然后将 libaConfig 包含在 dummy 的 CMakeLists.txt 中,以获取有关如何构建 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 时都会自动重新构建并重新链接到 dummy。 如果您喜欢这种方法,那么您唯一应该做的就是在 liba' CMakeLists.txt 中使用 PARENT_SCOPE 选项定义您需要的变量(参见 set() 命令手册)。

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

      【讨论】:

      • 我不愿意专门使用这种方法,因为我正在交叉编译 android ARM 二进制文件。如果我安装库,它不会把我的系统弄乱吗?
      • 嗯,不用make install来获取生成的libAConfig.cmake文件。
      • 除了libAConfig.cmake之外,您可能还想生成一个libALibraryDepends.cmake,其中包含库目标的ìmport定义以及依赖库。
      猜你喜欢
      • 2017-04-04
      • 1970-01-01
      • 2013-02-17
      • 1970-01-01
      • 1970-01-01
      • 2022-08-24
      • 1970-01-01
      • 1970-01-01
      • 2023-03-30
      相关资源
      最近更新 更多