makefile入门

参考

教程(文档和视频),讲解详细

makefile入门

首先要掌握gcc 命令、动态库静态库的编译链接过.
程;在此基础上,学习makefile的基本规则,语法,能够写一个冗余(难看)的makefile文件;最后逐渐掌握常用变量、模式匹配(公式)、函数的用法

1. gcc命令

要点:
1)编译要指定头文件,调试参数-g也是在此期间进行;
2)链接要指定库路径和库文件;
3)动态库要放在可执行文件可搜索到的路径,-L并不能指定搜索路径;
4)库的后缀不能错,linux(.a/.so)和win(.lib/.dll)后缀都不同;
5)指定库文件不用加后缀,如果要加格式为-l:libxxx.lib

#静态库制作
g++ -c src/*.cpp  #生成二进制文件,如果debug记着加上 -g
ar rcs lib/libscalc.lib *.o #打包静态库,注意后缀名,linux是libcalc.a

#动态库制作
g++ -c -fpic src/*.cpp 
g++ shared *.o lib/libdcalc.dll

#链接
g++ main.cpp -Iinclude -Llib -ilibscalc -o staic.exe
g++ main.cpp -Iinclude -Llib -ilibdcalc -o share.exe
g++ main.cpp -Iinclude -Llib -i:libdcalc.dll -o share.exe

2. 基本规则

目标:目标顶格写,后面是冒号(冒号后面是依赖)
依赖:依赖是用来产生目标的原材料。
命令:命令前面一定是Tab,不能是顶格,也不能说多个空格。命令就是要生成那个目标需要做的动作。

target1,target2... : depend1,depend2, ...
	command
	......
	 ......

一个简单示例: 文件都在一个目录下:

# 生成可执行文件
static.exe : main.cpp libcalc.lib
	g++ main.cpp -Iinclude -L. -llibcalc -o static.exe 
#制作静态库
libcalc.lib : add.o div.o mult.o sub.o
	ar rcs libcalc.lib add.o div.o mult.o sub.o 

add.o : add.cpp
	gcc add.cpp -c -Iinclude -o add.o

div.o : div.cpp
	gcc div.cpp -c -Iinclude -o div.o

mult.o : mult.cpp
	gcc mult.cpp -c -Iinclude -o mult.o

sub.o : sub.cpp
	gcc sub.cpp -c -Iinclude -o sub.o

3. 变量

自定义变量:obj+= a.o b.o c.o src := a.cpp b.cpp c.cpp target ?= app.exe include = ./include

四个赋值符号依次为,追加,赋值(常规意义上的 =),如果被赋值过则忽略本次赋值,类似宏替换(影响全局)
预定义变量(静态库和g++编译选项):AR; ARFLAGS; CPPFLAGS;
主要是掌握几个常用的自动变量(用来代替规则中的目标文件和依赖文件,只能在规则的命令中使用)

$*目标文件名称,不含扩展名
$@目标文件名称,含扩展名
$<依赖文件,依赖项中第一个
$+依赖文件,所有,包含重复,按出现的先后顺序
$^依赖文件,所有,不重复
$?依赖文件,比目标文件时间戳晚,文件之间以空格分开

4. 模式匹配

用于根据文件名或路径的模式自动匹配文件并执行相应的操作。模式匹配使用特殊的语法来指定模式,并可以匹配文件名、路径和其他规则中的模式。
以下是一些常见的模式匹配语法:
简单的模式匹配:使用通配符来匹配文件名。例如,.c表示匹配所有以.c为后缀的源代码文件。
复杂模式匹配:使用更复杂的正则表达式来匹配文件名或路径。例如,[A-Z]
.c表示匹配所有以大写字母开头并以.c为后缀的源代码文件。
变量替换:使用波浪线(~)来表示变量的占位符,可以在匹配时将其替换为相应的变量值。例如,%.o: %.c表示将目标文件名的占位符%o替换为目标文件名,依赖项名的占位符%c替换为依赖项名。

,规则中使用 %.c;搜索可以使用 *.c ,变量替换使用%.c

CPPFLAGES = -c -O2  -g
%.o : %.cpp
	g++ CPPFLAGES $< -o $@  

5. 函数

几个基本函数要掌握: (实例看后面练习1)
将指定目录和要求的文件展开,返回值包含路径和文件名:$(wildcard *.cpp);
替换文件名() $(patsubst %.cpp,%.o,$(wildcard *.cpp)); 可以用于条件替换:$(patsubst lib/libcalc.lib,lib/Specialities/libcalc.lib,lib/libcalc.lib)
还有一种文件名替换方式: $(SRC:%.cpp=%.o) ;
去掉路径 dir=$(notdir ./test/src/a,cpp)
添加路径 $(addprefix $(ROOT)/src/,$(OBJ))

6.其他

6.1 使用shell命令

makefile 可以执行 shell命令 比如常用的 rm -f echo${CURDIR} 等,要使用.PHONY声明伪目标;
ROOT:=$(shell pwd) 记录makefile所在路径 ;但如果是在windows的mingw环境下,使用该命令得到的路径无法使用。
rm -f $(shell find -name "*.o") rm -f obj/*.o) 这里一定要加上-f,避免因为前面命令没有正确执行导致后面命令无法执行。

6.2 文件名

如果名字不是makefile/Makefile;则需要 -f参数 指定文件名:make -f Makefile_test

6.3 时间戳

make通过时间戳(文件生成的时间)来判断命令是否需要重新执行;

6.4 伪目标

clean:
	rm -f $(shell find -name "*.o")
	rm -f $(TARGET) 

此时clean 没有依赖,时间戳检测不过,因此不会执行该命令,需要在shell中执行:make clean
如果想要自动执行,需要将其声明为伪目标 .PHONY:clean ;但是如果文件中存在其他规则,也不会自动执行;没搞明白

CFLAGS +=-I$(CURDIR)/include
CFLAGS	+= -Wall -Werror -O2
CFLAGS	+= -g
CFLAGS	+= -c -o
## 依赖项
LDFLAGS += -L$(CURDIR)/lib
LDFLAGS += -llibcalc

SRC = $(wildcard ./*.cpp ./src/*.cpp) 
OBJ  := $(SRC:%.cpp=%.o) 

TARGET := bin/app
$(TARGET) : $(OBJ)
	g++ $^ -o $@

%.o:%.cpp
#g++ $< -c -Iinclude -o $@
	g++ $(CFLAGS) $@ $<

.PHONY:showpath
showpath:
	@echo "CURDIR:"$(CURDIR)
 	@echo "CFLAGS:"$(CFLAGS)
 	@echo "LDFLAGS:"$(LDFLAGS)
 	@echo "SRC:"$(SRC)
 	@echo "OBJ:"$(OBJ)

#.PHONY:clean
clean:
	rm  -f src/*.o
	rm  -f bin/*.exe

7.关于路径问题

makefile 路径搜索:vpath和VPATH变量

.表示makefile文件当前路径,./../表示上一级目录,$(CURDIR)可以用来表示当前目录的路径;

总结

  • 格式:
  • 赋值:
  • 自动变量
  • 函数
  • 模式匹配

练习/测试

 tree D:\C++\CPP_EXERCISES\TEST_GCC /f 
D:\C++\CPP_EXERCISES\TEST_GCC
|   main.cpp
|   makefile
|
+---bin 		 #放可执行文件
+---build  
+---include 		#头文件
|       head.h
|
+---lib   			#库文件
\---src
        add .cpp
        div.cpp
        mult.cpp
        sub.cpp

测试1 :函数测试

### 测试,函数返回结果、变量值、生成文件的路径问题
ROOT := ${shell pwd}
## 编译项
CFLAGS +=-I$(ROOT)/include
CFLAGS	+= -Wall -Werror -O2
CFLAGS	+= -g
CFLAGS	+= -c -o
## 依赖项
LDFLAGS += -L$(ROOT)/lib
LDFLAGS += -llibcalc
# wildcard patsubst addprefix 等函数使用
SRC = $(wildcard ./src/*.cpp) 
SRCS =  $(notdir $(wildcard src/*.cpp ))
OBJ = $(patsubst %.cpp, %.o, $(SRCS))
OBJS  := $(SRC:%.cpp=%.o) 
OBJSS :=  $(addprefix $(ROOT)/src/,$(OBJ))
.PHONY:showpath
showpath:
	@echo "CURDIR:"$(CURDIR)
	@echo "ROOT:"$(ROOT)    #windows 系统不能用这种路径,可以用CURDIR
	@echo "CFLAGS:"$(CFLAGS)
	@echo "LDFLAGS:"$(LDFLAGS)
	@echo "SRC:"$(SRC)
	@echo "SRCS:"$(SRCS)
	@echo "OBJ:"$(OBJ)
	@echo "OBJS:"$(OBJS)
	@echo "OBJSS:"$(OBJSS)
#输出结果
$ MAKE
CURDIR:D:/c++/cpp_exercises/test_gcc
ROOT:/d/c++/cpp_exercises/test_gcc    
CFLAGS:-I/d/c++/cpp_exercises/test_gcc/include -Wall -Werror -O2 -g -c -o
LDFLAGS:-L/d/c++/cpp_exercises/test_gcc/lib -llibcalc

SRC:./src/add.cpp ./src/mult.cpp ./src/sub.cpp ./src/div.cpp
SRCS:add.cpp mult.cpp sub.cpp div.cpp
OBJ: add.o mult.o sub.o div.o
OBJS:./src/add.o ./src/mult.o ./src/sub.o ./src/div.o

测试2: 编译、链接两步走


CFLAGS +=-I$(CURDIR)/include
CFLAGS	+= -Wall -Werror -O2
CFLAGS	+= -g
CFLAGS	+= -c -o
## 依赖项
LDFLAGS += -L$(CURDIR)/lib
LDFLAGS += -llibcalc

SRC = $(wildcard ./*.cpp ./src/*.cpp) 
OBJ  := $(SRC:%.cpp=%.o) 

TARGET := bin/app
$(TARGET) : $(OBJ)
	g++ $^ -o $@

%.o:%.cpp
#g++ $< -c -Iinclude -o $@
	g++ $(CFLAGS) $@ $<
make后文件目录如下:多出来的用 ** **标记
D:\C++\CPP_EXERCISES\TEST_GCC
|   main.cpp
|   **main.o**
|   makefile
|
+---bin
|       **app.exe**
|
+---build
+---include
|       head.h
|
+---lib
\---src
        add.cpp
        **add.o**
        div.cpp
        **div.o**
        mult.cpp
        **mult.o**
        sub.cpp
        **sub.o**

测试3: 生成静态库

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值