ubuntu18.04下--CMake教程

CMake 教程

文章目录

  • CMake 教程
    • 0. CMake安装及卸载
    • 1. 创建简单的实例
    • 2. CMake 重要参数
    • 3. 构建项目结构
    • 4. CMakeList.txt 模板

CMake是开源、跨平台的构建工具,可以让我们通过编写简单的配置文件去生成本地的CMakeList.txt,这个配置文件是独立于运行平台和编译器的,这样就不用亲自去编写Makefile了,而且配置文件可以直接拿到其它平台上使用,无需修改,非常方便。

参考网站:

[1] Cmake官网

[2] Cmake github网址

[3] Cmake Documentation

[4] Linux下CMake简明教程

[5] Modern CMake 简体中文版

0. CMake安装及卸载

  1. sh文件安装
sudo sh cmake-3.22.3-linux-x86_64.sh --prefix=/usr/local --exclude-subdir
  1. apt-get 方式
sudo apt-get install cmake
  1. 源代码方式
# 下载 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
  1. CMake 卸载
sudo apt-get autoremove cmake

1. 创建简单的实例

  • main.cpp
#include 

int main() {

    std::cout << "Hello, World!" << std::endl;

    return 0;

}
  • CMakeList.txt
# cmake 最低版本需求
cmake_minimum_required(VERSION 3.13)

# 工程名称
project(cmake_study)

# 设置
set(CMAKE_CXX_STANDARD 11)

# 编译源码生成目标
add_executable(cmake_study src/main.cpp)
  • 文件列表
    ubuntu18.04下--CMake教程_第1张图片

  • CMake 编译

# 创建文件夹
mkdir build
# cd 到build 文件夹
cd build
# cmake 编译CMakeList.txt
cmake .. 
# make 产生可执行文件
make
# 运行
./cmake_study 

ubuntu18.04下--CMake教程_第2张图片
ubuntu18.04下--CMake教程_第3张图片

2. CMake 重要参数

  • 设置项目名称 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 #运行可执行文件
  • 生成静态库dll
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实例

引入opencv头文件和库说明:

按照此路径,cmake可以找到一个opencv的设置文件OpenCVConfig.cmake,其中预定义变量OpenCV_INCLUDE_DIRSOpenCV_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 …else…
    if (expression)
    COMMAND1(ARGS ...)
    COMMAND2(ARGS ...)
    ... 
    else (expression)
    COMMAND1(ARGS ...) 
    COMMAND2(ARGS ...)
    ... 
    endif (expression)
    
    • while
    WHILE(condition)
    COMMAND1(ARGS ...) 
    COMMAND2(ARGS ...) 
    ... 
    ENDWHILE(condition)
    
    • Foreach
    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)
    

3. 构建项目结构

.
├── CMakeList.txt
├── include/
│   ├── CMakeList.txt
│   ├── includeA.h
│   └── includeB.h
├── lib/
│   ├── CMakeList.txt
│   ├── libA.c
│   └── libB.c
└── main.cpp
  • 第一层CMakeList.txt
# 内容如下:
# 项目名称 
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目录里面生成的
  • lib目录CMakeList.txt
#内容如下: 
#将当前的源文件名字都添加到DIR_LIB变量下
aux_source_director(. DIR_LIB)
#生成库文件命名为test
add_libraries(test ${DIR_LIB})
  • include目录
# include目录的CMakeLists可以为空,因为我们已经将include目录包含在第一层的文件里面

4. CMakeList.txt 模板

  • 单个CMakeList.txt模板
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)
  • 多个CMakeList.txt模板

ubuntu18.04下--CMake教程_第4张图片

  • 主目录

文件目录结构;
├── 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
// 子目录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
// 子目录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})

ubuntu18.04下--CMake教程_第5张图片

你可能感兴趣的:(CMake,c++,linux,visual,studio)