Github代码链接
"#"
在Makefile中是注释
gcc/g++的常见指令
gcc -c #选项:只编译不链接,仅生成目标文件
gcc -o #选项:指定输出文件 -o tag obj / obj -o tag
gcc -O #优化编译
gcc -E #选项:生成预处理文件
gcc -S #选项:生成汇编文件
gcc -l #选项:手动添加链接库
gcc -L #使用-L选项,为 GCC 增加另一个搜索链接库的目录 $ gcc main.c -o main.out -L/usr/lib -lm
gcc -I #指定 include 包含文件的搜索目录
gcc -g # 生成调试信息,该程序可以被调试器调试
gcc -Wall #开启错误警告
安装 tree 查看项目文件结构
$ sudo snap install tree
user@XXX:~/Workspace/Codefiles/00Hello$ tree
.
├── helloworld
├── helloworld.cpp
├── helloworld.o
├── Makefile
└── oldMakefile
├── v1_Makefile
├── V2_Makefile
└── V3_Makefile
1 directory, 7 files
在终端输入 make
接:
-n
(Makefile将要执行的内容)
-k
(发现错误依然执行,而不是在第一个错误处停止)
-f filename
(指定其他文件作为Makefile文件执行)
特殊宏或关节字
$*:不包括后缀名的当前依赖文件的名称
$+:所有的依赖文件,以空格分开,并以出现的先后为序,可能包含重复的依赖文件
$<:第一个依赖文件的名称
$:所有时间戳比目标文件晚的依赖文件,并以空格分开
$@:目标文件的完整名称
$^:所有不重复的目标依赖文件,以空格分开
-: :告诉make命令忽略所有的错误
@:告诉make在执行命令前不要将改命令显示在标准输出上
可以通过 KEY = value
来定义变量,并通过$(KEY)
或${KEY}
来引用变量
1.1. 书写规范
Makefile由创建目标/依赖和目标指令构成
目标文件:依赖文件helloworld : helloworld.o
[TAB]指令
g++ -o helloworld helloworld.o
伪目标(不生成目标文件的指令)
.PHONY:
clean:
rm -rf helloworld.o helloworld.s helloworld.i
第一个目标是程序的最终目标
最后只需在项目目录Makefile文件夹下终端
make
即刻执行Makefile
输入:make clean
执行清除伪目标指令
# Version: 1.0 书写规范
# 目标文件:依赖文件
# [TAB]指令
# 例子
# 目标 : 依赖
helloworld : helloworld.o #第一个目标是最终目标
g++ helloworld -o helloworld.o
helloworld.o : helloworld.s
g++ -c helloworld.s -o helloworld.o
helloworld.s : helloworld.i
g++ -S helloworld.i -o helloworld.s
helloworld.i : helloworld.cpp
g++ -E helloworld.cpp -o helloworld.i
.PHONY:
clean:
rm -rf helloworld.o helloworld.s helloworld.i
注意若使用vim文本编辑器Makefile:3:***遗漏分隔符。停止
$ sudo vi ~/.vimrc
" 在vimrc文件中设置tab
set tabstop = 4
"不要使用空格替换tab
set expandtab "将tab转换成空格
set expandtab
变量化使得Makefile编写更加规则化,类似于宏
通过=/ += / :=对变量进行赋值,依次是等于/追加/横等于 使用变量通过: $(变量名)针对version 1.0进行升级
# Version: 2.0 变量
# TAR = 目标文件
# TAR += 目标文件2
# OBJ = 依赖文件
# CC:=g++ #针对横定不便的指令开头
# $(变量) 来使用变量
TAR = helloworld
OBJ = helloworld.o
CXX := g++
$(TAR) : $(OBJ)
$(CXX) $(OBJ) -o $(TAR)
$(OBJ) : helloworld.cpp
$(CXX) -c helloworld.cpp -o $(OBJ)
.PHONY:
clean:
rm $(OBJ)
cleanall:
rm $(OBJ) $(TAR)
1.3 隐含规则
通过通配符来格式化依赖及指令
# %.c/ %.o/ *.c/ *.o
因此针对Version 2进行升级
# Version: 3.0 通配符 使用隐含规则:通配符来改进Makefile
# 隐含规则:使用通配符%.c/ %.o/ *.c/ *.o
TAR = helloworld
OBJ = helloworld.o
CXX := g++
$(TAR) : $(OBJ)
$(CXX) $(OBJ) -o $(TAR)
*.o : *.cpp
$(CXX) -c *.cpp -o *.o
.PHONY:
clean:
rm $(OBJ)
cleanall:
rm $(OBJ) $(TAR)
1.4. 通配符
$^: 所有的依赖对象
$@: 所有的目标文件
$<: 所有依赖文件的第一个文件
# Version: 4.0 通配符 $^/$@/$<
# 1、%.cpp %.o 说有的cpp 所有的object
# 2、$^:所有的依赖对象 $@所有的目标文件 $<所有依赖文件的第一个文件
TAR = helloworld
OBJ = helloworld.o
CXX := g++
#CFLAGS = -g -Wall -O
$(TAR) : $(OBJ)
$(CXX) $^ -o $@
*.o : *.cpp
$(CXX) -c $^ -o $@
# $(CXX) $(CFLAGS) -c $^
.PHONY:
clean:
rm $(OBJ)
cleanall:
rm $(OBJ) $(TAR)
1.5 多级目录下Makefile
工程文件夹下不同目录引用问题
.cpp
依赖的.h
在同文件夹: #include "*.h"
.h在上级文件夹: #include "../*.h"
.cpp
在src
,.h
在include: #include "../include/*.h"
当头文件和源文件被分开./src
./include
~/Workspace/Codefiles/00standproject$ tree
├── include
│ ├── cube.h
│ ├── geometry.h
│ └── sphere.h
├── Makefile
├── obj
│ └── Makefile
└── src
├── cube.cpp
├── main.cpp
└── sphere.cpp
3 directories, 8 files
// main.cpp中引用cube.h sphere.h
#include "../include/cube.h"
#include "../include/sphere.h"
一级Makefile
# 主目录下Makefile
GXX :=g++
OBJ = cube.o sphere.o main.o
TOPDIR := $(PWD) # 声明顶级目录
OBJDIR := $(TOPDIR)/obj # 声明中间文件目录
SRCDIR := $(TOPDIR)/src # 声明源文件目录
BINDIR := $(TOPDIR)/bin # 声明编译生成执行文件目录
SUBDIR := obj# 拥有Makefile的子目录
INCPATH := include # 声明头文件目录
OBJHEAD := $(INCPATH)/cube.h $(INCPATH)/geometry.h $(INCPATH)/sphere.h #声明头文件
OBJLINK := --std=c99
BIN := pro1-app # 声明生存执行文件名词
export GXX TOPDIR OBJDIR BINDIR BIN OBJLINK OBJ INCPATH SRCDIR # 声明全局变量以便次级Makefile使用
CFLAGS = -g -Wall -O
all:CHECKDIR $(SUBDIR)
CHECKDIR:
mkdir -p $(SUBDIR) $(BINDIR) # 检查目录,-p 没有则自动生成
$(SUBDIR) : RUN
make -C $@ # 跳转次级目录并执行其中Makefile
RUN:
clean:
rm $(BINDIR)/$(BIN) $(OBJDIR)/*.o
# 谨慎使用 rm -rf
次级目录的Makefile
$(BINDIR)/$(BIN) : $(OBJ)
$(GXX) $^ -o $@ $(OBJHEAD) $(OBJLINK) # 链接生成最终可执行文件并存放入bin文件夹
@echo "==========build end=============="
# 编译src中的源文件,生存各中间依赖文件,并存放到obj目录
cube.o : $(SRCDIR)/cube.cpp
$(GXX) $(CFLAGS) -c $(SRCDIR)/cube.cpp -I $(INCPATH)
sphere.o : $(SRCDIR)/sphere.cpp
$(GXX) $(CFLAGS) -c $(SRCDIR)/sphere.cpp -I $(INCPATH)
main.o : $(SRCDIR)/main.cpp
$(GXX) $(CFLAGS) -c $(SRCDIR)/main.cpp -I $(INCPATH)
@echo "==========build object=========="
最终项目树:
~/Workspace/Codefiles/00standproject$ tree
.
├── bin
│ └── pro1-app
├── include
│ ├── cube.h
│ ├── geometry.h
│ └── sphere.h
├── Makefile
├── obj
│ ├── cube.o
│ ├── main.o
│ ├── Makefile
│ └── sphere.o
└── src
├── cube.cpp
├── main.cpp
└── sphere.cpp
4 directories, 12 files