简单记录一下Makefile和CMake的用法

简单记录一下Makefile和CMake的用法

由于Linux/Unix环境下的C++开发,特别是涉及到多模块的编译时,完全离不开Makefile,所以简单了解一下后在这边做个记录。

Makefile

假设在一个工程中有4个文件,分别为:

main.cpp

1
2
3
4
5
6
7
8
9
10
11
#include <iostream>
#include "functions.h"
using namespace std;
int main()
{
printhello();

cout << "This is main:" << endl;
cout << "The factorial of 5 is:" << factorial(5) << endl;
return 0;
}

printhello.cpp

1
2
3
4
5
6
7
8
9
#include <iostream>
#include "functions.h"
using namespace std;

void printhello()
{
int i;
cout << "Hello World!" << endl;
}

factorial.cpp

1
2
3
4
5
6
7
8
9
10
#include <iostream>
#include "functions.h"

int factorial(int n)
{
if(n == 1)
return 1;
else
return n * factorial(n - 1);
}

和头文件functions.h

1
2
3
4
5
#ifndef _FUNCTIONS_H_
#define _FUNCTIONS_H_
void printhello();
int factorial(int n);
#endif

直接使用g++ main.cpp是无法实现编译的,因为链接的时候会出错。

而使用g++ main.cpp factorial.cpp printhello.cpp又实在是太麻烦。

此时就可以使用这种方式:

1
2
3
4
5
6
g++ main.cpp -c
g++ factorial.cpp -c
g++ printhello.cpp -c
# 只编译不链接,生成3个.o文件
g++ *.o
# 将所有.o文件链接,生成一个a.out

其实这种方式就是理解Makefile操作原理的关键

下面通过4个Makefile的写法进一步理解。

Version 0x00

1
2
hello: main.cpp printhello.cpp factorial.cpp
g++ -o hello main.cpp printhello.cpp factorial.cpp

hello = 目标 后面 = 依赖
通过时间判断文件是否是最新,再判断是否执行命令

Version 0x01

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
CXX = g++
TARGET = hello
OBJ = main.o printhello.o factorial.o

$(TARGET): $(OBJ)
$(CXX) -o $(TARGET) $(OBJ)

main.o: main.cpp
$(CXX) -c main.cpp

printhello.o: printhello.cpp
$(CXX) -c printhello.cpp

factorial.o: factorial.cpp
$(CXX) -c factorial.cpp

判断依赖关系

Version 0x02

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
CXX = g++
TARGET = hello
OBJ = main.o printhello.o factorial.o

CXXFLAGS = -c -Wall

$(TARGET): $(OBJ)
$(CXX) -o $@ $^
# $@=所在的行里面的目标 $^=所在的行里面的依赖

%.o: %.cpp
$(CXX) $(CXXFLAGS) $< -o $@
# $<=依赖里的第一个

.PHONY: clean
clean:
rm -f *.o $(TARGET)
#PHONY 如果正好有个文件叫clean,那么就不会执行下面的命令。所以取一个永远不会存在的文件名.PHONY

Version 0x03

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
CXX = g++
TARGET = hello
SRC = $(wildcard *.cpp)
# 将所有.cpp放进来
OBJ = $(patsubst %.cpp, %.o, $(SRC))
# 将SRC里的.cpp路径替换成.o

CXXFLAGS = -c -Wall

$(TARGET): $(OBJ)
$(CXX) -o $@ $^

%.o: %.cpp
$(CXX) $(CXXFLAGS) $< -o $@

.PHONY: clean
clean:
rm -f *.o $(TARGET)

CMake

由于Makefile所使用的编译命令都收到了平台的限制,为了实现跨平台,可以使用CMake来生成Makefile。

使用CMake只需要在工程目录下编写一个CMakeLists.txt的文件

CMakeLists.txt

1
2
3
4
5
cmake_minimum_required(VERSION 3.10)

project(hello)

add_executable(hello main.cpp factorial.cpp printhello.cpp)

之后只要在当前目录下使用cmake .就可以了。

但是此时又会有一个问题,那就是当前目录下会出现很多cmake生产的文件,会导致工作目录比较乱。
可以使用这样的方式解决,就是在工作目录中再建一个build的文件夹,把这些东西都丢进去。

1
2
3
mkdir build
cd build
cmake ..
作者

Jhuoer Yen

发布于

2022-12-02

更新于

2024-01-15

许可协议

评论

Your browser is out-of-date!

Update your browser to view this website correctly.&npsb;Update my browser now

×