Cmake之深入理解find_package()的用法

“轻松搞定CMake”系列之find_package用法详解中提到Module模式和Config模式的区别:

  • Module模式:find_package命令基础工作模式(Basic Signature),也是默认工作模式。
  • Config模式:find_package命令高级工作模式(Full Signature)。 只有在find_package()中指定CONFIG、NO_MODULE等关键字,或者Module模式查找失败后才会进入到Config模式。

Cmake之深入理解find_package()的用法中对Module模式和Config模式的区别的描述似乎和上面的描述不太符合】

https://www.jianshu.com/p/39fc5e548310
https://www.cnblogs.com/pandamohist/p/16177016.html

官方文档阅读

依赖项引入的方法,FetchContent和find_package()

  • find_package():库使用cmake、非cmake构建的都可以使用find_package()来引入。
    如果库是必要的,那么必须加上REQUIRED??
find_package(Catch2)
find_package(GTest REQUIRED)
find_package(Boost 1.79 COMPONENTS date_time)

1.79是版本,cmake如何检测版本对不对,检测文件名字吗??
COMPONENTS是个啥?

看不懂Module mode和Config mode的区别?
可以在cmake命令中指定使用哪种mode运行??

.pc文件和.cmake文件都是包含库文件和头文件,两者有什么区别??

什么叫components,是库文件吗??

如何写那种模式下的文件呢??

总结:Cmake之深入理解find_package()的用法

为了方便我们在项目中引入外部依赖包,cmake官方为我们预定义了许多寻找依赖包的Module,他们存储在path_to_your_cmake/share/cmake-<version>/Modules目录下。每个以Find<LibaryName>.cmake命名的文件都可以帮我们找到一个包。

【有些包会自动下载下来???】
cmake的安装路径中的path_to_your_cmake/share/cmake-<version>/Modules中含有一些cmake官方写的.cmake文件,如果linux中根本没有curl呢,如果curl安装在不知道什么地方呢?这些官方定义的.cmake为什么能起作用,什么时候起作用,什么时候不能起作用?

我的官方定义的.cmake文件在/usr/share/cmake-3.24/Modules

在Module模式中,cmake需要找到一个叫做Find.cmake的文件。这个文件负责找到库所在的路径,为我们的项目引入头文件路径和库文件路径。cmake搜索这个文件的路径有两个,一个是上文提到的cmake安装目录下的share/cmake-/Modules目录,另一个使我们指定的CMAKE_MODULE_PATH的所在目录。

find_package的含义:在CMakeLists.txt中使用CMAKE_MODULE_PATH指明.cmake文件所在目录,.cmake指明库文件和头文件所在目录。find_library用于指明查找哪个库。

find_package的两种模式,一种是Module模式,一种叫做Config模式。【看不懂两者的区别?】
Module模式:安装cmake的时候,cmake官方写的.cmake文件
Config模式:安装各种包的时候,各种包提供的.cmake文件。

【由以上的例子可以看到,对于原生支持Cmake编译和安装的库通常会安装Config模式的配置文件到对应目录,这个配置文件直接配置了头文件库文件的路径以及各种cmake变量供find_package使用。而对于非由cmake编译的项目,我们通常会编写一个Find.cmake,通过脚本来获取头文件、库文件等信息。通常,原生支持cmake的项目库安装时会拷贝一份XXXConfig.cmake到系统目录中,因此在没有显式指定搜索路径时也可以顺利找到。】??

官方文档
find_package的两种搜索模式:Module和Config,什么叫做搜索模式,搜索什么的呢??库文件和头文件所在的路径吗?
两种模式在.cmake文件的编写上有什么不同的吗?引用这两种搜索模式的.cmake文件的方法有什么不同吗??

Find.cmake 文件通常不由包本身提供。相反,它通常由包外部的东西提供,例如操作系统、CMake 本身,甚至是调用 find_package() 命令的项目。【为什么可以由包外部的东西提供,那包的开发和安装又不是cmake和操作系统进行的,那么怎么可以由包外的东西开发的??难道是说:使用cmake安装的应用,在安装的过程中cmake会检查此应用的.cmake文件是否在cmake的share中已经定义了??】
文中还提到这种方法,容易过时,那这种方法的意义是什么??

1.创建自己的xxxConfig.cmake,用于第三方使用

CMAKE_INSTALL_PREFIX:make install时的安装路径。不仅可以在CMakeLists.txt中使用,也可以在cmake命令上进行设置,如:
cmake -D CMAKE_INSTALL_PREFIX=/usr

参考:创建自己的xxxConfig.cmake,用于第三方使用

2.编写自己的Find.cmake模块

项目的目录结构:

├── libadd.cc
├── libadd.h
├── Makefile
└── test
    ├── addtest.cc
    ├── cmake
    │   └── FindADD.cmake
    └── CMakeLists.txt

具体内容如下:
libadd.h

int add(int i, int j);

libadd.cc

#include "libadd.h"
 
int add(int i, int j)
{
	return i + j;
}

Makefile

# 1、准备工作,编译方式、目标文件名、依赖库路径的定义。
CC = g++
CFLAGS  := -Wall -O3 -std=c++11 

OBJS = libadd.o #.o文件与.cpp文件同名
LIB = libadd.so # 目标文件名
INCLUDE = ./ # 头文件目录
HEADER = libadd.h # 头文件

all : $(LIB)

# 2. 生成.o文件 
$(OBJS) : libadd.cc
	$(CC) $(CFLAGS) -I ./ -fpic -c $< -o $@

# 3. 生成动态库文件
$(LIB) : $(OBJS)
	rm -f $@
	g++ $(OBJS) -shared -o $@ 
	rm -f $(OBJS)


# 4. 删除中间过程生成的文件 
clean:
	rm -f $(OBJS) $(TARGET) $(LIB)

# 5.安装文件
install:
	cp $(LIB) /usr/lib
	cp $(HEADER) /usr/include

编译和安装动态库:

make
sudo make install

addtest.cc

#include <stdio.h>
#include <stdlib.h>
#include "libadd.h"
 
int main(int argc, char *argv[]) 
{
	printf("1 + 2 = %d\n", add(1, 2));
	return 0;
}

CMakeLists.txt

cmake_minimum_required(VERSION 3.16)
project(test) 
# 将项目目录下的cmake文件夹加入到CMAKE_MODULE_PATH中,让find_pakcage能够找到我们自定义的函数库
set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake;${CMAKE_MODULE_PATH}")
add_executable(addtest addtest.cc)
find_package(ADD)
if(ADD_FOUND)
    target_include_directories(addtest PRIVATE ${ADD_INCLUDE_DIR})
    target_link_libraries(addtest ${ADD_LIBRARY})
else(ADD_FOUND)
    message(FATAL_ERROR "ADD library not found")
endif(ADD_FOUND)

FindADD.cmake

# 在指定目录下寻找头文件和动态库文件的位置,可以指定多个目标路径
find_path(ADD_INCLUDE_DIR libadd.h /usr/include/ /usr/local/include ${CMAKE_SOURCE_DIR}/ModuleMode)
find_library(ADD_LIBRARY libadd.so  /usr/lib/ /usr/local/lib/ ${CMAKE_SOURCE_DIR}/ModuleMode)

if (ADD_INCLUDE_DIR AND ADD_LIBRARY)
	set(ADD_FOUND TRUE)
endif (ADD_INCLUDE_DIR AND ADD_LIBRARY)

编译和执行:

cd test
mkdir build
cd build
cmake ..
make
./addtest
输出:
1 + 2 = 3
posted @ 2022-10-27 11:31  好人~  阅读(4120)  评论(1编辑  收藏  举报