记:由浅入深Makefile学习

Halona ·
更新时间:2024-09-20
· 548 次阅读

Makefile预备1.1. 书写规范1.2. 变量1.3 隐含规则1.4. 通配符1.5 多级目录下Makefile 预备

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

1.2. 变量

变量化使得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" .cppsrc.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
作者:waveluozu



makefile

需要 登录 后方可回复, 如果你还没有账号请 注册新账号