cmake 简单配置文件示例

Posted

技术标签:

【中文标题】cmake 简单配置文件示例【英文标题】:cmake simple config file example 【发布时间】:2018-04-16 12:39:11 【问题描述】:

现在我有一个我自己制作的库,我想在另一个 CMake c++ 项目中使用它。它像这样存在于我的计算机中。

$MY_LIB_PATH\include
$MY_LIB_PATH\lib\x86\debug\lib-files
$MY_LIB_PATH\lib\x86\release\lib-files
$MY_LIB_PATH\lib\x64\debug\lib-files
$MY_LIB_PATH\lib\x64\release\lib-files

让 CMake find_package 知道这些的基本配置文件是什么样的?我希望它会非常简单,因为它没有太多信息可以提供。 But this page just make my head hurt.

对不起,我决定复制源代码,所以我真的不知道应该接受哪个答案。

【问题讨论】:

你看过this吗? 【参考方案1】:

不要自己写配置;使用 CMake 的 export 命令。它过于宽泛,无法在此处完整介绍,但这里有一个来自我的一个项目的修改示例:

install(TARGETS
        your_target
    EXPORT YourPackageConfig
    ARCHIVE DESTINATION $CMAKE_INSTALL_LIBDIR
    LIBRARY DESTINATION $CMAKE_INSTALL_LIBDIR
    RUNTIME DESTINATION $CMAKE_INSTALL_BINDIR
)
export(TARGETS
        your_target
    NAMESPACE YourPackage::
    FILE "$CMAKE_CURRENT_BINARY_DIR/YourPackageConfig.cmake"
)
install(EXPORT
        YourPackageConfig
    DESTINATION "$CMAKE_INSTALL_DATADIR/YourPackage/cmake"
    NAMESPACE YourPackage::
)

这将为您创建配置文件,因此其他项目可以通过find_package 使用它。

find_package(YourPackage REQUIRED)
target_link_libraries(foo YouprPackage::your_target)

这会自动处理IMPORTED 目标,还允许您嵌入编译器标志、包含路径、库依赖项,甚至哪些文件是您界面的一部分(基本上,任何属于INTERFACE 属性的文件)。

【讨论】:

你确定这有效吗?导出命令的手册说“此命令创建的文件特定于构建树,永远不应安装”。事实上,如果我尝试这样做,我会收到一条错误消息,说“文件...是由 export() 命令生成的。它可能不是用 install() 命令安装的”。 @GeorgP。 - 哪个命令给你这个问题? export ($CMAKE_CURRENT_BINARY_DIR/YourPackageConfig.cmake) 创建的文件与正在安装的文件 ($CMAKE_INSTALL_DATADIR/YourPackage/cmake) 不同。 啊,是的,我的错。但是 YourPackageConfig.cmake 到底是用来做什么的呢? 这个 sn-p 将创建两个文件,都名为 YourPackageConfig.cmake,只是在不同的位置。 export 创建的包让其他包无需先安装即可使用您的工件,尽管我从未在简短的测试之外使用过它;我发现make && make install 更简洁,它与我正在处理的任何包的更常见用法相匹配。 导出路径不应该是$CMAKE_INSTALL_DATADIR/cmake/YourPackage吗?因为对于系统范围安装的标准情况,这会将它放在 /usr/share/cmake/YourPackage 中,它由 cmake 找到。这是例如pybind11 做了什么。【参考方案2】:

在库的根目录下放一个“$libname-config.cmake”。

然后在该文件中添加一个 IMPORTED 目标。

有一个 libprotobuf 的例子。

add_library(libprotobuf STATIC IMPORTED GLOBAL)

set_target_properties(libprotobuf PROPERTIES 
    IMPORTED_LOCATION "$CMAKE_CURRENT_SOURCE_DIR/prebuilt/android/$ANDROID_ABI/libprotobuf.a"
    IMPORTED_LINK_INTERFACE_LIBRARIES "$ZLIB_LIBRARIES;$CMAKE_THREAD_LIBS_INIT"
    INTERFACE_INCLUDE_DIRECTORIES "$CMAKE_CURRENT_SOURCE_DIR/src")

将 Env 或 CMake 变量“$libname_DIR”设置为“$MY_LIB_PATH”

使用它。

find_package($libname)
#.......
target_link_libraries(main $libname)

【讨论】:

为什么这些建议不在官方文档中?为什么他们必须如此糟糕(文档)? Thx btw - 简单且有效。另外我建议使用 CMAKE_CURRENT_LIST_DIR 而不是 CMAKE_CURRENT_SOURCE_DIR 来使这个子项目可重定位。【参考方案3】:

也许这个older doc 可能更轻量级。还有这个tutorial 或this other one。最后一个可能是最简单的。

希望不会增加更多的痛苦:-)

按照文档应该给出大致如下的内容(假设您的库是mylib):

MyLib/MyLibConfig.cmake.in

# - Config file for the MyLib package
# It defines the following variables
#  MYLIB_INCLUDE_DIRS - include directories for MyLib
#  MYLIB_LIBRARIES    - libraries to link against
#  MYLIB_EXECUTABLE   - the bar executable

# Compute paths
get_filename_component(MYLIB_CMAKE_DIR "$CMAKE_CURRENT_LIST_FILE" PATH)
set(MYLIB_INCLUDE_DIRS "@CONF_INCLUDE_DIRS@")

# Our library dependencies (contains definitions for IMPORTED targets)
if(NOT TARGET mylib AND NOT MyLib_BINARY_DIR)
  include("$MYLIB_CMAKE_DIR/MyLibTargets.cmake")
endif()

# These are IMPORTED targets created by MyLibTargets.cmake
set(MYLIB_LIBRARIES mylib)

MyLib/MyLibConfigVersion.cmake.in

set(PACKAGE_VERSION "@MYLIB_VERSION@")

# Check whether the requested PACKAGE_FIND_VERSION is compatible
if("$PACKAGE_VERSION" VERSION_LESS "$PACKAGE_FIND_VERSION")
  set(PACKAGE_VERSION_COMPATIBLE FALSE)
else()
  set(PACKAGE_VERSION_COMPATIBLE TRUE)
  if ("$PACKAGE_VERSION" VERSION_EQUAL "$PACKAGE_FIND_VERSION")
    set(PACKAGE_VERSION_EXACT TRUE)
  endif()
endif()

主 MyLib/CMakeLists.txt

...

set(MYLIB_MAJOR_VERSION 0)
set(MYLIB_MINOR_VERSION 1)
set(MYLIB_PATCH_VERSION 0)
set(MYLIB_VERSION
  $MYLIB_MAJOR_VERSION.$MYLIB_MINOR_VERSION.$MYLIB_PATCH_VERSION)

...

add_library(mylib SHARED mylib.c ...)

...

install(TARGETS mylib
  # IMPORTANT: Add the mylib library to the "export-set"
  EXPORT MyLibTargets
  RUNTIME DESTINATION "$INSTALL_BIN_DIR" COMPONENT bin
  LIBRARY DESTINATION "$INSTALL_LIB_DIR" COMPONENT shlib
  PUBLIC_HEADER DESTINATION "$INSTALL_INCLUDE_DIR/mylib"
    COMPONENT dev)

...

# The interesting stuff goes here
# ===============================

# Add all targets to the build-tree export set
export(TARGETS mylib
  FILE "$PROJECT_BINARY_DIR/MyLibTargets.cmake")

# Export the package for use from the build-tree
# (this registers the build-tree with a global CMake-registry)
export(PACKAGE MyLib)

# Create the MyLibConfig.cmake and MyLibConfigVersion files
file(RELATIVE_PATH REL_INCLUDE_DIR "$INSTALL_CMAKE_DIR"
   "$INSTALL_INCLUDE_DIR")
# ... for the build tree
set(CONF_INCLUDE_DIRS "$PROJECT_SOURCE_DIR" "$PROJECT_BINARY_DIR")
configure_file(MyLibConfig.cmake.in
  "$PROJECT_BINARY_DIR/MyLibConfig.cmake" @ONLY)
# ... for the install tree
set(CONF_INCLUDE_DIRS "\$MYLIB_CMAKE_DIR/$REL_INCLUDE_DIR")
configure_file(MyLibConfig.cmake.in
  "$PROJECT_BINARY_DIR$CMAKE_FILES_DIRECTORY/MyLibConfig.cmake" @ONLY)
# ... for both
configure_file(MyLibConfigVersion.cmake.in
  "$PROJECT_BINARY_DIR/MyLibConfigVersion.cmake" @ONLY)

# Install the MyLibConfig.cmake and MyLibConfigVersion.cmake
install(FILES
  "$PROJECT_BINARY_DIR$CMAKE_FILES_DIRECTORY/MyLibConfig.cmake"
  "$PROJECT_BINARY_DIR/MyLibConfigVersion.cmake"
  DESTINATION "$INSTALL_CMAKE_DIR" COMPONENT dev)

# Install the export set for use with the install-tree
install(EXPORT MyLibTargets DESTINATION
  "$INSTALL_CMAKE_DIR" COMPONENT dev)

【讨论】:

以上是关于cmake 简单配置文件示例的主要内容,如果未能解决你的问题,请参考以下文章

CMake 交叉编译示例

CMake 交叉编译示例

配置 C++ 应用程序构建的简单方法

CMake简单用法

一个简单的cmake例子

怎样编写Cmake的配置文件Cmakelist.txt