C++ > Cmake

目录

编译器

多文件编译与链接

Makefile构建系统

Makefile 的构建系统 CMake

CMake 中的静态库与动态库

头文件

递归引入头文件

CMake子模块

子模块头文件处理

CMake其他选项

作为纯头文件引入

作为子模块引入

CMake 引用系统中预安装的第三方库


编译器

厂商		C		C++
GNU			gcc		g++	

main.cpp 

#include <cstdio>

int main() {
    printf("Hello, world!\n");
    return 0;
}

编译器, 是一个根据源代码生成机器码的程序

g++ main.cpp -o a.out

调用编译器程序g++, 读取main.cpp中源码, 根据C++标准生成相应的机器指令码, 输出到a.out可执行文件

./a.out

执行可执行文件

考究命令

objdump -D a.out | less
//将可执行文件a.out 转成汇编语言, less命令是的查看可以上下滚动
richard@rich:~/workspace$ ldd a.out 
        linux-vdso.so.1 (0x00007ffdce762000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fa4d24d1000)
        /lib64/ld-linux-x86-64.so.2 (0x00007fa4d2ac4000)

多文件编译与链接

hello.cpp

#include <cstdio>

void hello() {
    printf("Hello, world\n");
}

 main.cpp

#include <cstdio>

void hello();

int main() {
    hello();
    return 0;
}
g++ -c hello.cpp -o hello.o
g++ -c main.cpp -o main.o
g++ hello.o main.o -o a.out

使用 -c 选项指定生成临时的对象文件,再根据一系列对象文件进行链接,得到最终的a.out

如果单独改动hello.cpp文件的话,只需要执行

g++ -c hello.cpp -o hello.o
g++ hello.o main.o -o a.out

Makefile构建系统

make 这个程序,只需写出不同文件之间的依赖关系,和生成各文件的规则

特点

1. 当只更新了hello.cpp时只会重新编译hello.o, 不需要将main.o重新编译
2. 能够自动并行地发起对hello.cpp和main.cpp的编译, 加快编译速度(make -j)
3. 用通配符批量生成构建规则,避免针对每个.cpp和.o重复写 g++ 命令(%.o: %.cpp)

文件结构

richard@rich:~/workspace$ tree
.
├── hello.cpp
├── main.cpp
└── Makefile

 Makefile内容,

a.out: hello.o main.o
	g++ hello.o main.o -o a.out

hello.o: hello.cpp
	g++ -c hello.cpp -o hello.o

main.o: main.cpp
	g++ -c main.cpp -o main.o

执行make

richard@rich:~/workspace$ make
g++ -c hello.cpp -o hello.o
g++ -c main.cpp -o main.o
g++ hello.o main.o -o a.out

无更新执行make

richard@rich:~/workspace$ make
make: 'a.out' is up to date.

Makefile 的构建系统 CMake

跨平台的 CMake 的产生, 只需编写CMakeLists.txt,就能够在调用时生成当前系统所支持的构建系统

目录结构

richard@rich:~/workspace$ tree
.
├── CMakeLists.txt
├── hello.cpp
├── main.cpp
└── run.sh

 CMakeLists.txt内容

cmake_minimum_required(VERSION 3.12)
project(hellocmake LANGUAGES CXX)

add_executable(a.out main.cpp hello.cpp)

读取当前目录的 CMakeLists.txt,并在 build 文件夹下生成 build/Makefile

cmake -B build

make -C build 和 cmake -B build一样, 但更跨平台

让 make 读取 build/Makefile,并开始构建 a.out

cmake --build build

执行可执行文件 a.out

build/a.out

合并起来放在 run.sh 中, 

cmake -B build
cmake --build build --target a.out
build/a.out

build 目录下生成的文件列表


-rwxrwxr-x 1 richard richard  8368 5月  31 14:06 a.out
-rw-rw-r-- 1 richard richard 12377 5月  31 14:06 CMakeCache.txt
drwxrwxr-x 6 richard richard  4096 5月  31 14:06 CMakeFiles
-rw-rw-r-- 1 richard richard  1622 5月  31 14:06 cmake_install.cmake
-rw-rw-r-- 1 richard richard  5752 5月  31 14:06 Makefile

CMake 中的静态库与动态库

add_executable 生成可执行文件
add_library 生成库文件
# 生成静态库 libtest.a
add_library(test STATIC source1.cpp source2.cpp)  

# 生成动态库 libtest.so
add_library(test SHARED source1.cpp source2.cpp)  

创建库以后, 要在某个可执行文件中使用该库只需要,
# 为 myexec 链接库 libtest.a
target_link_libraries(myexec PUBLIC test)  

CMakeLists.txt内容,

cmake_minimum_required(VERSION 3.12)
project(hellocmake LANGUAGES CXX)

add_library(hellolib STATIC hello.cpp)
add_executable(a.out main.cpp)
target_link_libraries(a.out PUBLIC hellolib)

生成的文件列表,

richard@rich:~/workspace/build$ ls -ll
total 48
-rwxrwxr-x 1 richard richard  8368 5月  31 14:56 a.out
-rw-rw-r-- 1 richard richard 12377 5月  31 14:56 CMakeCache.txt
drwxrwxr-x 7 richard richard  4096 5月  31 14:56 CMakeFiles
-rw-rw-r-- 1 richard richard  1622 5月  31 14:56 cmake_install.cmake
-rw-rw-r-- 1 richard richard  1690 5月  31 14:56 libhellolib.a
-rw-rw-r-- 1 richard richard  6209 5月  31 14:56 Makefile

头文件

hello.cpp

#include <cstdio>

void hello() {
    printf("Hello, world\n");
}

hello.h

void hello();

main.cpp

#include <cstdio>

#include "hello.h"

int main() {
    hello();
    return 0;
}

other.cpp

#include <cstdio>

#include "hello.h"

void otherfunc() {
    hello();
}

run.sh

cmake -B build
cmake --build build --target a.out
build/a.out

CMakeLists.txt

cmake_minimum_required(VERSION 3.12)
project(hellocmake LANGUAGES CXX)

add_library(hellolib STATIC hello.cpp)
add_executable(a.out main.cpp other.cpp)
target_link_libraries(a.out PUBLIC hellolib)

递归引入头文件

在 C++ 中常常用到很多的类, 和函数一样, 类的声明也会被放到头文件中
有时候我们的函数声明需要使用到某些类, 需要用到声明了该类的头文件, 需要递归地 #include 

MyClass.h

struct MyClass {
    int m_number;
};

hello.h

#include "MyClass.h"

void hello(MyClass mc);

hello.cpp

#include <cstdio>

#include "hello.h"

void hello(MyClass mc) {
    printf("Hello, my number is %d!\n", mc.m_number);
}

main.cpp

#include <cstdio>

#include "hello.h"
#include "MyClass.h"

int main() {
    MyClass mc;
    mc.m_number = 42;
    hello(mc);
    return 0;
}

CMakeLists.txt

cmake_minimum_required(VERSION 3.12)
project(hellocmake LANGUAGES CXX)

add_library(hellolib STATIC hello.cpp)
add_executable(a.out main.cpp)
target_link_libraries(a.out PUBLIC hellolib)

如果多个头文件都引用了 MyClass.h, 那么 MyClass 会被重复定义两遍
解决方案, MyClass.h内容如下,

#ifndef MYCLASS_H
#define MYCLASS_H
struct MyClass {
    int m_number;
};
#endif

或者在头文件前面加上一行, #pragma once

#pragma once

struct MyClass {
    int m_number;
};

CMake子模块

复杂的工程中, 需要划分子模块

把 hellolib 库的源代码移到 hellolib 文件夹下, 该目录下CMakeLists.txt 定义了 hellolib 的生成规则

根目录可以使用 CMake 的 add_subdirectory 添加子目录, 子目录也包含一个 CMakeLists.txt,其中定义的库在 add_subdirectory 之后就可以使用

目录结构如下, 

richard@rich:~/workspace$ tree
.
├── CMakeLists.txt
├── hellolib
│   ├── CMakeLists.txt
│   ├── hello.cpp
│   └── hello.h
├── main.cpp
└── run.sh

 hellolib 目录下 CMakeLists.txt,

add_library(hellolib STATIC hello.cpp)

根目录下 CMakeLists.txt,

cmake_minimum_required(VERSION 3.12)
project(hellocmake LANGUAGES CXX)

add_subdirectory(hellolib)

add_executable(a.out main.cpp)
target_link_libraries(a.out PUBLIC hellolib)

子模块头文件处理

hello.h 在 hellolib 子文件夹中, main.cpp 需要改成 #include "hellolib/hello.h"
通过 target_include_directories 指定的路径会被视为与系统路径等价

hellolib/CMakeLists.txt

add_library(hellolib STATIC hello.cpp)
target_include_directories(hellolib PUBLIC .)

main.cpp

#include <cstdio>

#include <hello.h>

int main() {
    hello();
    return 0;
}

CMake其他选项

target_include_directories(myapp PUBLIC /usr/include/eigen3)	# 添加头文件搜索目录
target_link_libraries(myapp PUBLIC hellolib)					# 添加要链接的库
target_add_definitions(myapp PUBLIC MY_MACRO=1)					# 添加一个宏定义
target_add_definitions(myapp PUBLIC -DMY_MACRO=1)				# 与 MY_MACRO=1 等价
target_compile_options(myapp PUBLIC -fopenmp)					# 添加编译器命令行选项
target_sources(myapp PUBLIC hello.cpp other.cpp)				# 添加要编译的源文件

作为纯头文件引入

目录结构

-rwxrw-rw- 1 richard richard  156 4月  13 08:23 CMakeLists.txt
drwxrwxrwx 3 richard richard 4096 5月  30 18:08 glm
-rwxrw-rw- 1 richard richard  270 4月  13 08:23 main.cpp
-rwxrw-rw- 1 richard richard   62 4月  13 08:23 run.sh

使用target_include_directories 引入

CMakeLists.txt内容,

cmake_minimum_required(VERSION 3.12)
project(hellocmake LANGUAGES CXX)

add_executable(a.out main.cpp)
target_include_directories(a.out PUBLIC glm/include)

作为子模块引入

作为 CMake 子模块引入, 即 通过 add_subdirectory

方法就是把那个项目(以fmt为例)的源码放到你工程的根目录, 这些库较友好支持作为子模块引入

-rwxrw-rw- 1 richard richard  166 4月  13 08:23 CMakeLists.txt
drwxrwxrwx 8 richard richard 4096 5月  30 18:08 fmt
-rwxrw-rw- 1 richard richard  169 4月  13 08:23 main.cpp
-rwxrw-rw- 1 richard richard   62 4月  13 08:23 run.sh

 CMakeLists.txt

cmake_minimum_required(VERSION 3.12)
project(hellocmake LANGUAGES CXX)

add_subdirectory(fmt)

add_executable(a.out main.cpp)
target_link_libraries(a.out PUBLIC fmt)

CMake 引用系统中预安装的第三方库

以 opencv 为例

find_package(OpenCV REQUIRED)
target_link_libraries(ImageShow PRIVATE ${OpenCV_LIBS})

Ubuntu  安装 opencv ,请参考 Ubuntu 搭建C++ OpenCV 4.6.0和cmake编译

一个显示图片的C++程序,构建项目, 项目结构

richard@rich:~/workspace$ tree
.
├── 1.png
├── CMakeLists.txt
├── main.cpp
└── run.sh

进入ImageShow目录,在目录下新建main.cpp文件

main.cpp

#include <iostream>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
using namespace cv;
using namespace std;
int main(int argc, char** argv )
{
    Mat image;
    image = imread( argv[1], 1 );
    namedWindow("Display Image", WINDOW_AUTOSIZE );
    imshow("Display Image", image);
    waitKey(0);
    return 0;
}

CMakeLists.txt

#cmake needs this line
cmake_minimum_required(VERSION 3.1)

#Define project name
project(ImageShow)

#Find OpenCV, you may need to set OpenCV_DIR variable
#to the absolute path to the directory containing OpenCVConfig.cmake file
#via the command line or GUI
find_package(OpenCV REQUIRED)

#Enable C++11
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED TRUE)

#Declare the executable target built from your sources
add_executable(ImageShow main.cpp)

#Link your application with OpenCV libraries
target_link_libraries(ImageShow PRIVATE ${OpenCV_LIBS})

run.sh

cmake -B build
cmake --build build --target ImageShow
build/ImageShow 1.png

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值