前言
本文以实用为第一目标,将给出一个 M a c O S MacOS MacOS 编译 C / C C/C C/C++ 工程的固定模板,以便读者可以迅速上手!
文章主要如下分为三部分:
- 为什么需要 M a k e f i l e Makefile Makefile?
- 如何编写 M a k e f i l e Makefile Makefile?
- M a c O S MacOS MacOS 下编译 C / C C/C C/C++ 工程的固定模板
如果觉得文章对你有帮助,请点个赞再走!(•̀ᴗ•́)و ̑̑
为什么需要 M a k e f i l e Makefile Makefile?
M a k e f i l e Makefile Makefile 的出现主要是由于在大型的 C / C C/C C/C++ 工程中,经常会出现文件相互依赖的情况。举个例子, A A A 文件调用了 B B B 文件中的 类 / 函数,因此我们需要将 A , B A,B A,B 文件统一链接在一起形成最终的可执行文件。
正是由于上述情况的存在,使得我们必须将工程中所有文件链接在一起,而手工一条一条命令敲又非常费时,因此我们需要 M a k e f i l e Makefile Makefile,在我们给定编译顺序后自动帮助我们完成编译。
我们将以下面的三份代码为例来介绍在 M a c O S MacOS MacOS 下使用 M a k e f i l e Makefile Makefile 的方法。
- A . c p p A.cpp A.cpp
#include <iostream>
#include "B.h"
using namespace std;
int main() {
cout << add(1, 2) << endl;
return 0;
}
- B . h B.h B.h
#ifndef B_H
#define B_H
int add(int a, int b);
#endif
- B . c p p B.cpp B.cpp
#include <iostream>
#include "B.h"
int add(int a, int b) {
return a + b;
}
由此不难发现,想要让 A . c p p A.cpp A.cpp 文件能够正确执行,我们需要将这三个文件统一链接在一起!如果一条一条命令输的话,我们需要依次执行下述命令。
g++ -c A.c
g++ -c B.c
g++ -o main A.o B.o
显然一条一条命令输非常麻烦,因此我们需要 M a k e f i l e Makefile Makefile 来简化这个过程!
如何编写 M a k e f i l e Makefile Makefile?
我们以上述的例子为例,简要介绍我们的固定模板!
- 文件结构
- 两个大文件夹: b u i l d build build、 s r c src src
-
b
u
i
l
d
:
build:
build: 分为两个小文件夹,
b
i
n
bin
bin、
o
b
j
e
c
t
s
objects
objects
- b i n : bin: bin: 放最终的可执行文件
- o b j e c t s : objects: objects: 放 s r c src src 中的文件所生成的 . o .o .o 文件
- s r c : src: src: 工程文件
- 最外层:
M
a
k
e
f
i
l
e
Makefile
Makefile、
m
a
i
n
main
main(最终可执行文件的链接文件)
-
M
a
k
e
f
i
l
e
Makefile
Makefile 语法规则
$@:
目标文件$^:
所有依赖文件$<
第一个依赖文件- 编译语法规则
targets:
文件名,以空格分开,可以使用通配符command:
命令行,如果其不与 targets:prerequisites \text{targets:prerequisites} targets:prerequisites 在一行,则必须以 T a b Tab Tab 键卡头,如果和 targets:prerequisites \text{targets:prerequisites} targets:prerequisites 在一行,则可以用分号作为分隔prerequisites:
目标所依赖的文件,如果其中某个文件要比目标文件要新,则目标就被认为是 “过时的”,被认为是需要重新生成的- r e f : ref: ref: 《跟我一起写 Makefile \text{Makefile} Makefile》
targets: prerequisites
command
- 定义变量
- 文件路径
- 编译命令参数
- 最终目标文件
dest_dir = build
src_dir = src
obj_dir = $(dest_dir)/objects
bin_dir = $(dest_dir)/bin
CC = g++
RESULT = main
CFLAGS = -Wall -O3 -std=c++14
CFILES = A.cpp B.cpp
ofiles = $(CFILES:%.cpp=$(obj_dir)/%.o)
program = $(bin_dir)/$(RESULT)
$(program): $(ofiles)
- 产生
.
o
.o
.o 文件
- 第一句:输出编译信息
- 第二句:如果不存在路径上的文件夹,则创建文件夹
- 第三句:执行
g++ -c xxx.c
命令
# src 中所有 cpp 文件
$(obj_dir)/%.o: $(src_dir)/%.cpp
@echo ">>> Compiling" $< "<<<"
@if [ ! -d $(obj_dir) ]; then mkdir -p $(obj_dir); fi;
$(CC) $(CFLAGS) -c $< -o $@
# src 所有子文件夹中 cpp 文件
$(obj_dir)/%.o: $(src_dir)/*/%.cpp
@echo ">>> Compiling" $< "<<<"
@if [ ! -d $(obj_dir) ]; then mkdir -p $(obj_dir); fi;
$(CC) $(CFLAGS) -c $< -o $@
- 将所有
.
o
.o
.o 文件链接在一起生成可执行文件,并在最外层生成可执行文件的链接文件
- 第一句:输出编译信息
- 第二句:如果不存在路径上的文件夹,则创建文件夹
- 第三句:执行
g++ -o 目标可执行文件 xxx1.o xxx2.o ...
命令 - 第四句:将目标可执行文件链接到最外层
$(bin_dir)/%:
@echo ">>> Linking" $@ "<<<"
@if [ ! -d $(bin_dir) ]; then mkdir -p $(bin_dir); fi;
$(CC) -o $@ $^
ln -sf $@ $(notdir $@)
-
m
a
k
e
make
make
c
l
e
a
n
clean
clean 命令
- 当我们需要重新编译时,我们想要快速地删除上一次编译所产生的文件
- 我们可以自定义 m a k e make make c l e a n clean clean 命令,实现对上一次编译生成文件的快速清理
.PHONY: clean
clean:
rm -rf $(dest_dir)
rm -f $(RESULT)
M a c O S MacOS MacOS 下编译 C / C C/C C/C++ 工程的固定模板
至此,我们实现了一个简易的编译 C / C C/C C/C++ 工程的 M a k e f i l e Makefile Makefile 的固定模板。
每次需要编译,则先执行 m a k e make make c l e a n clean clean,再执行 m a k e make make
C C C 工程: g c c gcc gcc, C C C++ 工程: g g g++
增加需要编译的文件: 在 CFILES \text{CFILES} CFILES 变量后面继续添加即可
# $@: 目标文件, $^: 所有依赖文件, $<: 第一个依赖文件
# 语法规则:
# targets: prerequisites
# command
dest_dir = build
src_dir = src
obj_dir = $(dest_dir)/objects
bin_dir = $(dest_dir)/bin
CC = g++
RESULT = main
CFLAGS = -Wall -O3 -std=c++14
CFILES = A.cpp B.cpp
ofiles = $(CFILES:%.cpp=$(obj_dir)/%.o)
program = $(bin_dir)/$(RESULT)
$(program): $(ofiles)
$(bin_dir)/%:
@echo ">>> Linking" $@ "<<<"
@if [ ! -d $(bin_dir) ]; then mkdir -p $(bin_dir); fi;
$(CC) -o $@ $^
ln -sf $@ $(notdir $@)
$(obj_dir)/%.o: $(src_dir)/%.cpp
@echo ">>> Compiling" $< "<<<"
@if [ ! -d $(obj_dir) ]; then mkdir -p $(obj_dir); fi;
$(CC) $(CFLAGS) -c $< -o $@
$(obj_dir)/%.o: $(src_dir)/*/%.cpp
@echo ">>> Compiling" $< "<<<"
@if [ ! -d $(obj_dir) ]; then mkdir -p $(obj_dir); fi;
$(CC) $(CFLAGS) -c $< -o $@
.PHONY: clean
clean:
rm -rf $(dest_dir)
rm -f $(RESULT)
后记
本文的主要目标就是帮助读者快速迅速上手 M a c O S MacOS MacOS 下 C / C C/C C/C++ 工程的 M a k e f i l e Makefile Makefile 文件编写,因此并没有太多涉及 M a k e f i l e Makefile Makefile 的高阶用法,有兴趣的朋友可以仔细研读陈皓所写的《跟我一起写 Makefile \text{Makefile} Makefile》!
技术水平的不断提高在于不断实践,不断记录,持续精进!💪💪💪