CMake
是开源、跨平台的构建工具,可以让我们通过编写简单的配置文件去生成本地的CMakeList.txt
,这个配置文件是独立于运行平台和编译器的,这样就不用亲自去编写Makefile了,而且配置文件可以直接拿到其它平台上使用,无需修改,非常方便。
参考网站:
[1] Cmake官网
[2] Cmake github网址
[3] Cmake Documentation
[4] Linux下CMake简明教程
[5] Modern CMake 简体中文版
sudo sh cmake-3.22.3-linux-x86_64.sh --prefix=/usr/local --exclude-subdir
sudo apt-get install cmake
# 下载 cmake-3.22.3.tar.gz
wget https://github.com/Kitware/CMake/releases/download/v3.22.3/cmake-3.22.3.tar.gz
# 解压 cmake-3.21.0-rc2.tar.gz
tar -zxvf cmake-3.22.3.tar.gz
# 切换到 CMake 源目录并执行 bootstrap 脚本
cd cmake-3.22.3.tar.gz
./bootstrap --parallel=32
# 执行 make
make -j32
make install -j32
ln -s /usr/local/bin/cmake /usr/bin/cmake
# 软连接 ln [original filename] [link name]
# 查看 cmake 工具版本
cmake --version
sudo apt-get autoremove cmake
#include
int main() {
std::cout << "Hello, World!" << std::endl;
return 0;
}
# cmake 最低版本需求
cmake_minimum_required(VERSION 3.13)
# 工程名称
project(cmake_study)
# 设置
set(CMAKE_CXX_STANDARD 11)
# 编译源码生成目标
add_executable(cmake_study src/main.cpp)
# 创建文件夹
mkdir build
# cd 到build 文件夹
cd build
# cmake 编译CMakeList.txt
cmake ..
# make 产生可执行文件
make
# 运行
./cmake_study
project()
project(MyProject)
执行:project(MyProject),就是定义了一个项目的名称为:MyProject,对应的就会生成两个变量:_BINARY_DIR和_SOURCE_DIR,但是cmake中其实已经有两个预定义的变量:PROJECT_BINARY_DIR和PROJECT_SOURCR_DIR ;
# 内部构建
cmake ./
make
# 外部构建:外部构建的话, 中间文件和可执行文件会放在build目录
mkdir build
cd ./build
cmake ../
make
aux_sourcr_directory(<dir> <variable>)
aux_sourcr_directory(. DIR_SRCS)
# 将aux_sourcr_directory(. DIR_SRCS)当前目录下的源文件名字存放 到变量DIR_SRCS里面 ,如果源文件比较多,直接用DIR_SRCS变量即可
add_executable(exename srcname)
# exename : 生成的可执行文件的名字
# srcname : 源文件
add_executable(Demo ${DIR_SRCS})
# 可执行文件为 Demo
./Demo #运行可执行文件
add_library(libname [SHARED|STATIC|MODULE] [EXCLUDE_FROM_ALL] source1 source2 ... sourceN)
说明:
libname : 生成的库文件的名字
[SHARED|STATIC|MODULE] :生成库文件的类型(动态库|静态库|模块)
[EXCLUDE_FROM_ALL] :有这个参数表示该库不会被默认构建
source1 source2 … sourceN: 生成库依赖的源文件
# 实例1
add_library(ALib SHARE alib.cpp)
# 实例2
aux_sourcr_directory(. DIR_SRCS)
add_library(ALib STATIC ${DIR_SRCS})
添加头文件目录
# 方法1
target_include_directories(<target> [SYSTEM] [BEFORE] <INTERFACE|PUBLIC|PRIVATE> [items1...] [<INTERFACE|PUBLIC|PRIVATE> [items2...] ...])
# 当我们添加子项目之后还需要设置一个include路径,例子: eg:target_include_directories(RigelEditor PUBLIC ./include/rgeditor),表示给 RigelEditor 这个子项目添加一个库文件的路径
# 方法2
include_directories([AFTER|BEFORE] [SYSTEM] dir1 [dir2 …])
# [AFTER|BEFORE]:指定了要添加路径是添加到原有列表之前还是之后
# [SYSTEM]:若指定了system参数,则把被包含的路径当做系统包含路径来处理
# dir1 [dir2 …]把这些路径添加到CMakeLists及其子目录的CMakeLists的头文件包含项目中
include_directories("/opt/MATLAB/R2012a/extern/include")
引入opencv头文件和库说明:
按照此路径,cmake可以找到一个opencv的设置文件
OpenCVConfig.cmake
,其中预定义变量OpenCV_INCLUDE_DIRS
,OpenCV_VERSION
,OpenCV_LIBS
# ===================================================================================
# The OpenCV CMake configuration file
#
# ** File generated automatically, do not modify **
#
# Usage from an external project:
# In your CMakeLists.txt, add these lines:
#
# find_package(OpenCV REQUIRED)
# include_directories(${OpenCV_INCLUDE_DIRS}) # Not needed for CMake >= 2.8.11
# target_link_libraries(MY_TARGET_NAME ${OpenCV_LIBS})
#
# Or you can search for specific OpenCV modules:
#
# find_package(OpenCV REQUIRED core videoio)
#
# You can also mark OpenCV components as optional:
# find_package(OpenCV REQUIRED core OPTIONAL_COMPONENTS viz)
#
# If the module is found then OPENCV__FOUND is set to TRUE.
#
# This file will define the following variables:
# - OpenCV_LIBS : The list of all imported targets for OpenCV modules.
# - OpenCV_INCLUDE_DIRS : The OpenCV include directories.
# - OpenCV_COMPUTE_CAPABILITIES : The version of compute capability.
# - OpenCV_ANDROID_NATIVE_API_LEVEL : Minimum required level of Android API.
# - OpenCV_VERSION : The version of this OpenCV build: "3.4.6"
# - OpenCV_VERSION_MAJOR : Major version part of OpenCV_VERSION: "3"
# - OpenCV_VERSION_MINOR : Minor version part of OpenCV_VERSION: "4"
# - OpenCV_VERSION_PATCH : Patch version part of OpenCV_VERSION: "6"
# - OpenCV_VERSION_STATUS : Development status of this build: ""
#
# Advanced variables:
# - OpenCV_SHARED : Use OpenCV as shared library
# - OpenCV_INSTALL_PATH : OpenCV location
# - OpenCV_LIB_COMPONENTS : Present OpenCV modules list
# - OpenCV_USE_MANGLED_PATHS : Mangled OpenCV path flag
#
# Deprecated variables:
# - OpenCV_VERSION_TWEAK : Always "0"
#
# ===================================================================================
# ======================================================
# Version variables:
# ======================================================
# 实例:引入opencv库和头文件
cmake_minimum_required( VERSION 3.15 )
project( mainwindow )
# 添加c++ 11标准支持
set( CMAKE_CXX_FLAGS "-std=c++11" )
# 寻找OpenCV库
set(OpenCV_DIR /home/ubuntu/opt/opencv-3.4.6/release)
find_package( OpenCV 3 REQUIRED )
# 添加头文件
include_directories( ${OpenCV_INCLUDE_DIRS} )
add_executable( mainwindow mainwindow.cpp )
# 链接OpenCV库
target_link_libraries( mainwindow ${OpenCV_LIBS} )
# 第一个: 添加头文件
# 第二个:找到源文件
# 第三个:与目标链接起来
参考
:
使用CMake构建OpenCV项目
Linux 使用cmake构建OpenCV项目
# 命令1:
target_link_libraries(<target> [item1 [item2 [...]]] [[debug|optimized|general] <item>] ...)
# 命令2:
link_libraries()
# 给当前工程链接需要的库文件(全路径)
link_libraries(("/opt/MATLAB/R2012a/bin/glnxa64/ ") #必须添加带名字的全路径 libeng.so
set_target_properties()
set_target_properties(target1 target2 ... PROPERTIES 属性名称1 值 属性名称2 值 ... )
变量与缓存
变量的名称通常大写 ;
# 设置局部变量
set(MY_VARIABLE "value")
# 引用局部变量
${MY_VARIABLE}
缓存变量就是cache变量,相当于全局变量;
set(MY_CACHE_VALUE "cache_value" CACHE INTERNAL "THIS IS MY CACHE VALUE")
# THIS IS MY CACHE VALUE,这个字符串相当于对变量的描述说明,不能省略,但可 以自己随便定义
环境变量
# 设置环境变量:
set(ENV{variable_name} value)
# 获取环境变量:
$ENV{variable_name}
内置变量
CMake里面包含大量的内置变量,和自定义的变量相同,常用的有以下:
内置变量 | 说明 | 备注 |
---|---|---|
CMAKE_C_COMPILER | 指定C编译器 | |
CMAKE_CXX_COMPILER | 指定C++编译器 | |
EXECUTABLE_OUTPUT_PATH | 指定可执行文件的存放路径 | |
LIBRARY_OUTPUT_PATH | 指定库文件的放置路径 | |
CMAKE_CURRENT_SOURCE_DIR | 当前处理的CMakeLists.txt所在的路径 | |
CMAKE_BUILD_TYPE | 控制构建的时候是Debug还是Release | set(CMAKE_BUILD_TYPE Debug) |
CMAKE_SOURCR_DIR | CMAKE_SOURCR_DIR | |
CMAKE_BINARY_DIR | CMAKE_BINARY_DIR:内部构建指的是工程顶层目录,外部构建指的是工程发生编译的目录 | |
CMAKE_CURRENT_LIST_LINE | 输出这个内置变量所在的行 |
缓存
# 缓存就是之前提到的CMakeCache文件,参见:CMake命令行选项的设置- >CMakeCache.txt文件
CMake 基本语法
不太完善后续补充一下
if (expression)
COMMAND1(ARGS ...)
COMMAND2(ARGS ...)
...
else (expression)
COMMAND1(ARGS ...)
COMMAND2(ARGS ...)
...
endif (expression)
WHILE(condition)
COMMAND1(ARGS ...)
COMMAND2(ARGS ...)
...
ENDWHILE(condition)
FOREACH(loop_var arg1 arg2 ...)
COMMAND1(ARGS ...)
COMMAND2(ARGS ...)
...
ENDFOREACH(loop_var)
# 实例
AUX_SOURCE_DIRECTORY(. SRC_LIST)
FOREACH(F ${SRC_LIST})
MESSAGE(${F})
ENDFOREACH(F)
.
├── CMakeList.txt
├── include/
│ ├── CMakeList.txt
│ ├── includeA.h
│ └── includeB.h
├── lib/
│ ├── CMakeList.txt
│ ├── libA.c
│ └── libB.c
└── main.cpp
# 内容如下:
# 项目名称
project(main)
#需要的cmake最低版本
cmake_minium_required(VERSION 2.8)
#将当前目录下的源文件名都赋给DIR_SRC目录
aux_source_directories(. DIR_SRC)
#添加include目录
include_directories(include)
#生成可执行文件
add_executable(main ${DIR_SRC})
#添加子目录
add_subdirectories(lib)
#将生成的文件与动态库相连
target_link_libraries(main test)
#test是lib目录里面生成的
#内容如下:
#将当前的源文件名字都添加到DIR_LIB变量下
aux_source_director(. DIR_LIB)
#生成库文件命名为test
add_libraries(test ${DIR_LIB})
# include目录的CMakeLists可以为空,因为我们已经将include目录包含在第一层的文件里面
cmake_minimum_required(VERSION 3.5)
project(main)
## MESSAGE(FATAL_ERROR "${CMAKE_BUILD_TYPE}")
if(CMAKE_COMPILER_IS_GNUCC)
message("COMPILER IS GNUCC")
ADD_DEFINITIONS ( -std=c++11 )
endif(CMAKE_COMPILER_IS_GNUCC)
# 1. protobuf
# 1.1. Find required protobuf package
find_package(Protobuf REQUIRED)
if(PROTOBUF_FOUND)
message(STATUS "protobuf library found")
else()
message(FATAL_ERROR "protobuf library is needed but cant be found")
endif()
# 1.2. 生成pb.h、pb.cc必须要加的指令
include_directories(${PROTOBUF_INCLUDE_DIRS})
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR})
PROTOBUF_GENERATE_CPP(PROTO_SRCS PROTO_HDRS ${CMAKE_SOURCE_DIR}/include/protobuf/proto/config.proto)
# 1.3. head file path,头文件目录
message(${PROTO_HDRS})
INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include/protobuf)
# 2. CUDA
set(CUDA_DIR "/usr/local/cuda")
find_package(CUDA)
SET(CUDA_NVCC_FLAGS --disable-warnings;-std=c++11;-O3;-gencode arch=compute_75,code=sm_75)
## CUDA_ADD_LIBRARY(${PROJECT_NAME} SHARED)
message(${CUDA_NVCC_FLAGS})
# 3. opencv
## set(OpenCV_DIR "/data/wuh/open_source/opencv-3.4.6/build")
## find_package(OpenCV REQUIRED)
## include_directories(${OpenCV_INCLUDE_DIRS})
link_directories("/usr/local/lib")
include_directories("/usr/local/include/opencv4")
link_directories("")
#message(${SOURCE_FILES})
# 4. tensorRT
include_directories(/data/wuh/software/TensorRT-5.1.2.2/include)
link_directories(/data/wuh/software/TensorRT-5.1.2.2/lib)
link_directories(/data/wuh/project/test_algorithm_module/algorithm_module/build/)
LINK_LIBRARIES(algorithm)
# 5. 头文件
# 5.1. 定义函数,用于递归添加头文件
function(include_sub_directories_recursively root_dir)
if (IS_DIRECTORY ${root_dir}) # 当前路径是一个目录吗,是的话就加入到包含目录
message("include dir: " ${root_dir})
include_directories(${root_dir})
endif()
file(GLOB ALL_SUB RELATIVE ${root_dir} ${root_dir}/*) # 获得当前目录下的所有文件,让如ALL_SUB列表中
foreach(sub ${ALL_SUB})
if (IS_DIRECTORY ${root_dir}/${sub})
include_sub_directories_recursively(${root_dir}/${sub}) # 对子目录递归调用,包含
endif()
endforeach()
endfunction()
# 5.2. 添加头文件
include_sub_directories_recursively(${CMAKE_SOURCE_DIR}/include) # 对子目录递归调用,包含
MESSAGE(STATUS "CMAK_SOURCE_DIR" ${CMAKE_SOURCE_DIR})
# 6. 添加源文件
FILE(GLOB_RECURSE SOURCE_FILES ${CMAKE_SOURCE_DIR}/src/*.cu ${CMAKE_SOURCE_DIR}/src/*.cpp)
#message(${SOURCE_FILES})
# 7. 添加链接库
LINK_LIBRARIES(opencv_ml opencv_objdetect opencv_imgproc opencv_core opencv_highgui opencv_imgcodecs opencv_shape opencv_videoio opencv_video)
LINK_LIBRARIES(nvcaffe_parser nvinfer nvinfer_plugin nvparsers)
LINK_LIBRARIES(avcodec avformat swscale avutil)
LINK_LIBRARIES(cuda nvcuvid)
## LINK_LIBRARIES(algorithm)
LINK_LIBRARIES(glog)
# 8.source directory,源文件目录
AUX_SOURCE_DIRECTORY(test DIR_SRCS)
# 9. 设置环境变量,编译用到的源文件全部都要放到这里,否则编译能够通过,
# 但是执行的时候会出现各种问题,比如"symbol lookup error xxxxx , undefined symbol"
SET(ALL_SRCS ${DIR_SRCS} ${PROTO_SRCS} ${SOURCE_FILES} ${M_INCLUDE_FILES})
# 10.add executable file,添加要编译的可执行文件
## ADD_EXECUTABLE(${PROJECT_NAME} ${ALL_SRCS})
CUDA_ADD_EXECUTABLE(${PROJECT_NAME} ${ALL_SRCS})
# 11. 链接目标文件与库文件,添加可执行文件所需要的库,比如我们用到了libm.so(命名规则:lib+name+.so),就添加该库的名称
TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${PROTOBUF_LIBRARIES})
target_link_libraries(${PROJECT_NAME} /usr/local/cuda-10.1/lib64/libcudart.so)
target_link_libraries(${PROJECT_NAME} /usr/local/cuda-10.1/lib64/libcudnn.so)
文件目录结构;
├── CMakeLists.txt
├── fileA/
│ ├── CMakeLists.txt
│ ├── fileA.cpp
│ └── fileA.h
├── fileB/
│ ├── CMakeLists.txt
│ ├── fileB.cpp
│ └── fileB.h
└── main.cpp
// main.cpp
#include
#include "fileA.h"
#include "fileB.h"
int main()
{
fileA();
fileB();
return 0;
}
# 主目录下的CMakeLists.txt
cmake_minimum_required(VERSION 2.8.3)
project (cmake_files)
# Add header file include directories
include_directories(./fileA ./fileB)
# Add block directories
set(FILEA_SRC fileA/fileA.cpp)
set(FILEB_SRC fileB/fileB.cpp)
# Target
add_executable(cmake_files main.cpp ${FILEA_SRC} ${FILEB_SRC})
// 子目录FileA 头文件
#ifndef FILEA_H
#define FILEA_H
#include
void fileA();
#endif
// 子目录FileA 源文件
#include "fileA.h"
#include
void fileA()
{
std::cout<<"FileA--Start"<<std::endl;
}
# 子目录FileA下的CMakeLists.txt
aux_source_directory(. DIR_FILEA_SRCS)
add_library(fileA ${DIR_FILEA_SRCS})
// 子目录FileB 头文件
#ifndef FILEB_H
#define FILEB_H
#include
void fileB();
#endif
// 子目录FileB 源文件
#include "fileB.h"
#include
void fileB()
{
std::cout<<"FileB--Start"<<std::endl;
}
# 子目录FileB下的CMakeLists.txt
aux_source_directory(. DIR_FILEB_SRCS)
add_library(fileB ${DIR_FILEB_SRCS})