整个案例懒得话直接用这个操作看结果好了
rm -rf build
cmake -S . -B build
cmake --build build
1. Cmake 入门
#include <iostream>
int main()
{
std::cout << "Hello World!" << std::endl;
return 0;
}
同级目录
# 设置项目名字, 版本号(这个是自己项目的版本号), 项目描述, 项目语言
project(first_demo
VERSION 1.0.0
DESCRIPTION "项目描述"
LANGUAGES CXX)
# first_file: 生成的可执行文件的名字
# main.cpp 编译的CXX文件
add_executable(first_file main.cpp)
# -S 指定源码目录,-B 指定构建目录 这里 . 是当前目录的意思 -B 是指定构建目录
cmake -S . -B build
# 生成可执行文件, --build 在指定位置构建可执行文件
cmake --build build
案例
(base) root@ubuntu-01:/data/Github/trt_demo/1.Cmake/src/3.first_cmake# cmake -S . -B asd
-- The CXX compiler identification is GNU 7.5.0
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /data/Github/trt_demo/1.Cmake/src/3.first_cmake/asd
(base) root@ubuntu-01:/data/Github/trt_demo/1.Cmake/src/3.first_cmake# cmake --build asd
[ 50%] Building CXX object CMakeFiles/first_file.dir/main.cpp.o
[100%] Linking CXX executable first_file
[100%] Built target first_file
(base) root@ubuntu-01:/data/Github/trt_demo/1.Cmake/src/3.first_cmake# ./asd/first_file
Hello World!
2. 生成动态库链接
经过了顺序的实验, 给可执行文件添加东西放在定义可执行文件后面就行了
默认情况下,add_library创建的是静态库。如果需要创建动态库,需要使用 add_library( SHARED ),其中 SHARED 选项指定创建的是动态库。
add_library(Accountsssss SHARED "./account_dir/Account.cpp" "./account_dir/Account.h")
像这句话就是把"./account_dir/Account.cpp" “./account_dir/Account.h” 变成动态库 Accountsssss
(base) root@ubuntu-01:/data/Github/trt_demo/1.Cmake/src_back/6.build_together# tree .
.
├── account_dir
│ ├── Account.cpp
│ └── Account.h
├── CMakeLists.txt
└── test_account
└── main.cpp
#6.build_together/CMakeLists.txt`
# cmake的最低版本要求
cmake_minimum_required(VERSION 3.10)
# 项目信息
project(test_account)
# 添加可执行文件
add_executable(run_file "./test_account/main.cpp")
# 添加动态库
add_library(Accountsssss SHARED "./account_dir/Account.cpp" "./account_dir/Account.h")
# 添加链接库
target_link_libraries(run_file Accountsssss)
# 添加头文件
target_include_directories(run_file PUBLIC "./account_dir")
里面会生成一个动态库, 把他删掉了可执行文件也执行不了了
tree .
ldd build/run_file
(base) root@ubuntu-01:/data/Github/trt_demo/1.Cmake/src_back/6.build_together# tree .
.
├── account_dir
│ ├── Account.cpp
│ └── Account.h
├── build
│ ├── libAccountsssss.so
│ ├── Makefile
│ └── run_file
├── CMakeLists.txt
└── test_account
└── main.cpp
3 directories, 7 files
(base) root@ubuntu-01:/data/Github/trt_demo/1.Cmake/src_back/6.build_together# ldd build/run_file
linux-vdso.so.1 (0x00007fffa2b96000)
libAccountsssss.so => /data/Github/trt_demo/1.Cmake/src_back/6.build_together/build/libAccountsssss.so (0x00007f374897f000)
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f37485f6000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f37483de000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f3747fed000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f3747c4f000)
/lib64/ld-linux-x86-64.so.2 (0x00007f3748d84000)
3. Cmake中的PUBLIC PRIVATE INTERFACE
看一个案例
# 创建库, 这里创建了三个静态库
add_library(C c.cpp)
add_library(D d.cpp)
add_library(B b.cpp)
# C, D都是B的依赖项
# C是B的PUBLIC依赖项
target_link_libraries(B PUBLIC C)
# D是B的PRIVATE依赖项
target_link_libraries(B PRIVATE D)
# 添加可执行文件
add_executable(A a.cpp)
# 将B链接到A
target_link_libraries(A B)
C 是PUBLIC所以可以扩散到A
D是PRIVATE所以可以扩散到A
4. 变量和message()
根据自己的需求消除注释
# 最小的版本要求
cmake_minimum_required(VERSION 3.10)
# 项目名称
project(message_turtorial)
# 输出消息, 像python的print() 自动换行
message("输出消息")
message(输出消息1 " " 输出消息2) # 会做拼接的
# 设置变量, 变量的不同访问方法
set(My_Var "我的变量")
message("My_var = " ${
My_Var})
message("My_Var = ${My_Var}")
message("\{My_Var} = {My_Var}") # 转义字符就没法打印了
unset(My_Var)
message("My_Var = ${My_Var}") # 删除后输出为空
# 提供信息变量: 这些特殊字符串打错了就输出为空
message("项目名称: ${PROJECT_NAME}")
message("源码目录: ${CMAKE_SOURCE_DIR}")
message("编译目录: ${CMAKE_BINARY_DIR}")
message("当前CMakeList.txt文件路径: ${CMAKE_CURRENT_LIST_FILE}")
# 自己cmake一下才能够知道
# 不开的时候说呢工程的是*.a后缀的静态库文件
# 开了会生成*.so动态库文件, 在build的文件夹下面
set(BUILD_SHARED_LIBS ON)
# 描述系统的变量
message("是否是Windows系统: ${WIN32}")
message("是否是Linux系统: ${UNIX}")
message("系统名称: ${CMAKE_SYSTEM_NAME}")
# 生成库文件
add_library(${
PROJECT_NAME} Account.cpp Account.h)
全部的输出
输出消息
输出消息1 输出消息2
My_var = 我的变量
My_Var = 我的变量
{My_Var} = {My_Var}
My_Var =
项目名称: message_turtorial
源码目录: /data/Github/trt_demo/1.Cmake/src_back/7.message_var_demo
编译目录: /data/Github/trt_demo/1.Cmake/src_back/7.message_var_demo/build
当前CMakeList.txt文件路径: /data/Github/trt_demo/1.Cmake/src_back/7.message_var_demo/CMakeLists.txt
是否是Windows系统:
是否是Linux系统: 1
系统名称: Linux
5. Include
# 8.include_demo
cmake_minimum_required(VERSION 3.10)
project(include_demo)
message("调用include前的信息")
# include,引用一次就导入一次
# CMAKE_CURRENT_SOURCE_DIR这个是相对路径, CMakeList.txt
# 写一次就是调用一次, 这里调用了四次
include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/module_1.cmake")
include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/module_1.cmake")
include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/module_1.cmake")
include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/module_1.cmake")
message("调用include后的信息")
在对应的路径下有一个module_1.cmake
message("模块内部被调用")
5. if
在 CMake 中,缩进(也就是 tab 或空格)是用来控制代码块的,从而组织 CMakeLists.txt 文件的结构和逻辑。CMakeLists.txt 文件中的命令通常按照一定的层次结构排列,缩进的数量用于表示命令所属的代码块。一个代码块的缩进是它上一级代码块的缩进加上一个固定的缩进量(通常是一个制表符或四个空格),用于表示代码块的开始和结束。
在 CMake 中,endif() 是必需的,用于结束 if() 命令的代码块。if() 命令用于指定一个条件,如果这个条件成立,将会执行一段代码,否则将会执行另一段代码。在 if() 命令之后的代码块必须使用 endif() 命令来结束。
例如,在下面的代码片段中,if 和 else 命令是一个代码块的开始和结束,其中缩进用于将这两个命令与其它代码分离:
if (SOME_CONDITION)
# code to be executed if SOME_CONDITION is true
else ()
# code to be executed if SOME_CONDITION is false
endif ()
6. 用OPENCV的案例学习CMake
6.1 安装OPENCV
- 安装git
- 安装cmake, 亲测有效的实用帖子 (https://zhuanlan.zhihu.com/p/494120239)
- 打开终端,更新系统:
sudo apt update && sudo apt upgrade
- 安装所需依赖包:
sudo apt install build-essential cmake git libgtk2.0-dev pkg-config libavcodec-dev libavformat-dev libswscale-dev
sudo apt install python3-dev python3-numpy libtbb2 libtbb-dev libjpeg-dev libpng-dev libtiff-dev libdc1394-22-dev
- 从 GitHub 克隆 OpenCV 和 OpenCV Contrib 的源代码:
cd ~
git clone https://github.com/opencv/opencv.git
git clone https://github.com/opencv/opencv_contrib.git
- 创建一个构建目录,用于存放编译后的文件:
cd opencv
mkdir build
cd build
- 运行 CMake 来配置编译选项。请确保在以下命令中将 -D OPENCV_EXTRA_MODULES_PATH 参数设置为你的 opencv_contrib/modules 目录的实际路径。如果需要,可以通过在命令中添加 -D CMAKE_INSTALL_PREFIX=/your/custom/install/path 参数自定义安装路径:
cmake -D CMAKE_BUILD_TYPE=RELEASE \
-D CMAKE_INSTALL_PREFIX=/usr/local \
-D INSTALL_C_EXAMPLES=ON \
-D INSTALL_PYTHON_EXAMPLES=ON \
-D OPENCV_GENERATE_PKGCONFIG=ON \
-D OPENCV_EXTRA_MODULES_PATH=~/opencv_contrib/modules \
-D BUILD_EXAMPLES=ON ..
**注意: -D OPENCV_EXTRA_MODULES_PATH=~/opencv_contrib/modules \ **
这个contrib要写对路径
- 编译 OpenCV:
make -j$(nproc)
- 安装编译好的 OpenCV:
sudo make install
- 更新库链接:
sudo ldconfig
- 测试, 使用文本编辑器创建一个名为 opencv_version.cpp 的新文件,然后将以下代码粘贴到文件中:
#include <iostream>
#include <opencv2/core.hpp>
int main() {
std::cout << "OpenCV version: " << CV_VERSION << std::endl;
return 0;
}
g++ opencv_version.cpp -o opencv_version `pkg-config --cflags --libs opencv4`
./opencv_version
出现就说明成功了
OpenCV version: 4.7.0-dev
6.2 写一个CMakeList.txt
cmake_minimum_required(VERSION 3.10)
project(demo_opencv)
find_package(OpenCV REQUIRED)
if (OpenCV_FOUND)
message(STATUS "OpenCV library status:")
message(STATUS " libraries: ${OpenCV_LIBS}")
message(STATUS " include path: ${OpenCV_INCLUDE_DIRS}")
else ()
message(FATAL_ERROR "Could not find OpenCV")
endif ()
add_executable(demo_opencv main.cpp)
target_include_directories(demo_opencv PRIVATE ${OpenCV_INCLUDE_DIRS})
target_link_libraries(demo_opencv ${OpenCV_LIBS})