CMAKE 编写 FindXXX.cmake

首先为什么要写 FindXXX.cmake

对于一个大型项目,作为一个合格的开发人员来说,特别是C/C++开源人员。会一门编译工具非常重要。在一个大型项目中,使用过Makefile 的肯定感觉到问题就是,当项目庞大的时候,越到后面的库或者进程,依赖的头文件,库将会越来越多。在写makefile也是一件非常痛苦的一件事。相信这个问题,不只是在Makefile 中存在,cmake 中也会存在。
那么如果,可以让编译过后的库自己解决,自己的依赖。是不是就可以解决这个问题呢?

cmake提供这样的方法:
find_package.

find_package 将会根据开发人员提前写好的库或者进程的依赖,自己去加载依赖项,可以大大减少程序员工作量。
但是程序自己是不知道,库的依赖关系。这块信息需要开发人员提前写好,告诉程序。
大家可以写 FindXXX.cmake 或者 XXXXConfig.cmake XXXX-config.cmake

至于他们的先后顺序如下
下面这张图片来自网上。
在这里插入图片描述

由上图

find_package(<package> [version] [EXACT] [QUIET]
             [REQUIRED] [[COMPONENTS] [components...]]
             [CONFIG|NO_MODULE] # 这里就是关于配置是否使用 XXXConfig.cmake 的配置
             [NO_POLICY_SCOPE]
             [NAMES name1 [name2 ...]]
             [CONFIGS config1 [config2 ...]]
             [HINTS path1 [path2 ... ]]
             [PATHS path1 [path2 ... ]]
             [PATH_SUFFIXES suffix1 [suffix2 ...]]
             [NO_DEFAULT_PATH]
             [NO_CMAKE_ENVIRONMENT_PATH]
             [NO_CMAKE_PATH]
             [NO_SYSTEM_ENVIRONMENT_PATH]
             [NO_CMAKE_PACKAGE_REGISTRY]
             [NO_CMAKE_BUILDS_PATH]
             [NO_CMAKE_SYSTEM_PATH]
             [NO_CMAKE_SYSTEM_PACKAGE_REGISTRY]
             [CMAKE_FIND_ROOT_PATH_BOTH |
              ONLY_CMAKE_FIND_ROOT_PATH |
              NO_CMAKE_FIND_ROOT_PATH])

所以由上图可以看出来,直接使用 find_package的时候,先是尝试去找 FindXXX.cmake 文件。

那么这个文件一般在哪里呢?
一般存在
CMAKE_MODULE_PATH变量中.

下面是个人理解的编写过程,中间可能有错误,仅作参考。
先给大家看我的文件结构:

├── hello
│   ├── build
│   │   ├── libhello.so
│   │   └── Makefile
│   ├── CMakeLists.txt
│   ├── Findhello.cmake
│   ├── Findworld.cmake
│   ├── hello.cpp
│   └── hello.h
├── main
│   ├── CMakeLists.txt
│   └── main.cpp
└── world
    ├── build
    │   ├── libworld.so
    │   └── Makefile
    ├── CMakeLists.txt
    ├── Findworld.cmake
    ├── worldConfig.cmake
    ├── world.cpp
    └── world.h

简单介绍一下关系:
world 文件夹里面生成 libworld.so 仅仅包含

// 打印 world
void world(){
std::cout << "world" <<std::endl;
}

hello 文件里面生成 libhello.so

// 打印 hello
void hello(){
std::cout << "hello" << std::endl;
wolrd();
}

main 文件里面 生成 main 进程

int main(){
	hello();
}

我这里编写 Findhello.cmake Findworld.cmake去包含 world 和 hello 的文件依赖。
Findhello.cmake

set(hello_FOUND TRUE) # auto 如果成功 find 到,hello_FOUND =true。一般用法会判断 hello_FOUND 
set(hello_ROOT_DIR /home/lhd/work/testCmake/hello/)

find_path(hello_INCLUDE_DIR NAMES hello.h PATHS "${hello_ROOT_DIR}") 
#mark_as_advanced(hello_INCLUDE_DIR) # show entry in cmake-gui

find_library(hello_LIBRARY NAMES libhello.so PATHS "${hello_ROOT_DIR}/build") 
#mark_as_advanced(hello_LIBRARY) # show entry in cmake-gui

# use xxx_INCLUDE_DIRS and xxx_LIBRARIES in CMakeLists.txt

find_package(world )



set(hello_INCLUDE_DIRS ${hello_INCLUDE_DIR} ${world_INCLUDE_DIRS})
message(WARNING "======================hello_INCLUDE_DIRS=${hello_INCLUDE_DIRS}")
set(hello_LIBRARIES ${hello_LIBRARY} ${world_LIBRARIES})
message(WARNING "======================hello_LIBRARIES=${hello_LIBRARIES}")
#set(hello_INCLUDE_DIRS ${hello_INCLUDE_DIR} )
#set(hello_LIBRARIES ${hello_LIBRARY} )
message( "hello-config.cmake " ${hello_ROOT_DIR})

Findworld.cmake

set(world_FOUND TRUE) # auto 
set(world_ROOT_DIR /home/lhd/work/testCmake/world/)

find_path(world_INCLUDE_DIR NAMES world.h PATHS "${world_ROOT_DIR}") 
#mark_as_advanced(world_INCLUDE_DIR) # show entry in cmake-gui

find_library(world_LIBRARY NAMES libworld.so PATHS "${world_ROOT_DIR}/build") 
#mark_as_advanced(world_LIBRARY) # show entry in cmake-gui

# use xxx_INCLUDE_DIRS and xxx_LIBRARIES in CMakeLists.txt
set(world_INCLUDE_DIRS ${world_INCLUDE_DIR} )
set(world_LIBRARIES ${world_LIBRARY} )

message( "world-config.cmake " ${world_ROOT_DIR})

上面2个FindXXX.cmake 看出来
Findhello.cmake 依赖了 Findworld.cmake

所以main在find_package 的时候只需要,find hello 就可以了。
但是有一个地方要注意 Findhello.cmake Findworld.cmake 最好要在同一个目录。
如果不在同一个目录在cmake 的时候就需要
-DCMAKE_MODULE_PATH=“路径1;路径2”

cmake_minimum_required(VERSION 3.10)

project(main VERSION 1.0.0)

find_package(hello REQUIRED)
#find_package(world REQUIRED)

include_directories(${hello_INCLUDE_DIRS} )


set(CMAKE_CXX_STANDARD 11)

add_executable(${PROJECT_NAME}  main.cpp)

target_link_libraries(${PROJECT_NAME} ${hello_LIBRARIES} )

编译过程 :

cmake … -DCMAKE_MODULE_PATH=“path1”

如果某些同学,就是想使用 XXXConfig.cmake

也可以。按找上面的理论。如果你想使用 XXXConfig.cmake
你有2个选择,第一个只提供 XXXConfig.cmake.
因为 find_package 首先会去找 FindXXX.cmake . 如果找不到将会查找 XXXConfig.cmake 或者 XXX-config.cmake

第二个方法,直接指定使用的就是 XXXConfig.cmake
find_package(XXX CONFIG)
或者 find_package(XXX NO_MODULE)
find_package 将不会去查找 FindXXX.cmake,直接找 XXXConfig.cmake

但是对于 XXXConfig.cmake 需要注意使用另一个变量来指定路径
-DCMAKE_PREFIX_PATH=”path1;path2“

下面看一下修改后的
helloConfig.cmake

set(hello_FOUND TRUE) # auto 
set(hello_ROOT_DIR /home/lhd/work/testCmake/hello/)

find_path(hello_INCLUDE_DIR NAMES hello.h PATHS "${hello_ROOT_DIR}") 
#mark_as_advanced(hello_INCLUDE_DIR) # show entry in cmake-gui

find_library(hello_LIBRARY NAMES libhello.so PATHS "${hello_ROOT_DIR}/build") 
#mark_as_advanced(hello_LIBRARY) # show entry in cmake-gui

# use xxx_INCLUDE_DIRS and xxx_LIBRARIES in CMakeLists.txt

find_package(world CONFIG)


if (world_FOUND)
set(hello_INCLUDE_DIRS ${hello_INCLUDE_DIR} ${world_INCLUDE_DIRS})
message(WARNING "======================hello_INCLUDE_DIRS=${hello_INCLUDE_DIRS}")
set(hello_LIBRARIES ${hello_LIBRARY} ${world_LIBRARIES})
message(WARNING "======================hello_LIBRARIES=${hello_LIBRARIES}")
#set(hello_INCLUDE_DIRS ${hello_INCLUDE_DIR} )
#set(hello_LIBRARIES ${hello_LIBRARY} )
message( "hello-config.cmake " ${hello_ROOT_DIR})
endif()

worldConfig.cmake

set(world_FOUND TRUE) # auto 
set(world_ROOT_DIR /home/lhd/work/testCmake/world/)

find_path(world_INCLUDE_DIR NAMES world.h PATHS "${world_ROOT_DIR}") 
#mark_as_advanced(world_INCLUDE_DIR) # show entry in cmake-gui

find_library(world_LIBRARY NAMES libworld.so PATHS "${world_ROOT_DIR}/build") 
#mark_as_advanced(world_LIBRARY) # show entry in cmake-gui

# use xxx_INCLUDE_DIRS and xxx_LIBRARIES in CMakeLists.txt
set(world_INCLUDE_DIRS ${world_INCLUDE_DIR} )
set(world_LIBRARIES ${world_LIBRARY} )

message( "world-config.cmake " ${world_ROOT_DIR})

main的 CMakeLists.txt

cmake_minimum_required(VERSION 3.10)

project(main VERSION 1.0.0)

find_package(hello REQUIRED CONFIG)
#find_package(world REQUIRED)

include_directories(${hello_INCLUDE_DIRS} )

message(WARNING "======================hello_INCLUDE_DIRS=${hello_INCLUDE_DIRS}")
message(WARNING "======================hello_LIBRARIES=${hello_LIBRARIES}")
set(CMAKE_CXX_STANDARD 11)

add_executable(${PROJECT_NAME}  main.cpp)

target_link_libraries(${PROJECT_NAME} ${hello_LIBRARIES} )

使用:
cmake … -DCMAKE_PREFIX_PATH=”path1;path2“ 就可以了。
当然这个 path1 path2 就是 helloConfig.cmake 和 worldConfig.cmake 所在的路径。

最后附上源码:https://gitee.com/lu_han_dong/camke-find_package

  • 11
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值