C++

C++ (01) Makefile文件编写规范

Posted by xcTorres on December 24, 2020

在编译C++工程的时候,最常见的就是make编译,以及cmake编译。一直以来也没有专门学习过make以及cmake的规则,但是最近研究一个C++源码,代码是09年写的,需要调整makefile或者cmake文件,所以借此机会好好学习一下make和cmake。

Makefile

假如现在有hello_world.h头文件以及hello_world.cpp源文件如下

  • hello_world.h
1
2
3
4
5
6
7
8
9
10
11
12
//
// Created by Xie Chong on 23/12/20.
//

#ifndef MAKE_HELLO_WORLD_H
#define MAKE_HELLO_WORLD_H


void print();


#endif //MAKE_HELLO_WORLD_H
  • hello_world.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
//
// Created by Xie Chong on 23/12/20.
//


#include "hello_world.h"
#include <iostream>


void print(){
    std::cout << "hello world" << std::endl;
    return;
}

此时如果我们有一个main.cpp,在引入hello_world.h就可以调用hello_world的print方法了。

1
2
3
4
5
6
#include <hello_world.h>

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

当没有Makefile文件的时候,我们可以直接用g++命令来进行编译,其中-I.指引入当前路径为头文件路径,这样hello_world.h就被引入了。

1
g++ -o hellomake main.cpp hello_world.cpp -I .

这样就可以生成可执行文件hellomake,当我们调用./hellomake时,则可以打印出hello world来了。

1
2
3
4
./hellomake

// will print out hello world
// hello world

假如一个工程中需要编译很多个文件的时候,如果没有Makefile文件,就要不断的编写多个g++ -o语句,一旦某个文件更新,则要重复一步步手动编译,非常麻烦。这样就有了make的存在的原因。

Makefile_1

首先来看第一版本的Makefile文件,冒号之后标注所依赖的cpp源文件,而其下的编译命令必须以tab键隔开。Makefile文件写好后,此时输入make即可编译,并生成可执行文件hellomake。

1
2
hellomake: main.cpp hello_world.cpp
	g++ -o hellomake main.cpp hello_world.cpp -I.

Makefile_2

但是如此一来有个问题,一旦有一个cpp文件进行修改,Makefile_1的整个编译命令得全部重新进行非常繁琐。 接下来可以对Makefile_1进行下一步改进解耦,首先是将编译器定义变量CC,以及编译参数定义变量CXXFLAGS,如此一来有利于修改编译器类型以及添加新的C++编译参数;其次是hellomake所依赖的文件可以直接由.cpp替换成.o文件,make命令会根据.o的前缀名先自动独立编译其对应的.cpp文件,这样以来各个.o文件的编译不会互相影响,如果只有一个cpp文件修改,其他无关的可执行文件无需重新编译。

1
2
3
4
5
CC=g++
CXXFLAGS=-I.

hellomake: main.o hello_world.o
	$(CC) -o hellomake main.o hello_world.o -I.

Makefile_3

但是Makefile_2中,会出现这样一个问题,假如hello_world.h有了新的改动,.o文件不会随之重新编译。这样新的改动就无法生效。此时就得提前将.o文件与相应的头文件关联起来。如Makefile_3所示:其中DEPS可以把头文件的宏放置其中,%.o: %.c 中的\$@指的其实就是 %.o对应的文件, \$<指的是一系列参数里面的第一个,也就是%.c。

1
2
3
4
5
6
7
8
9
10
CC=g++
CXXFLAGS=-I.

DEPS = hell_world.h

%.o: %.c $(DEPS)
	$(CC) -c -o $@ $< $(CFLAGS)

hellomake: main.o hello_world.o
	$(CC) -o hellomake main.o hello_world.o

Makefile_4

Makefile_5



-->