一、makefile用意
一个大工程文件是成百上千的,一个个文件的去编译可想而知效率极其低下,使用Makefile实现自动编译,并且可避免已编译文件再次编译,大大的提升了软件的开发速度。
二、 makefile规则
2.1 命名与使用
名字为Makefile 或 makefile
使用指令:make
2.2 一个规则
编写规则:
目标:依赖条件
(一个 tab 缩进)命令
例:
a.out:a.o
gcc a.o -c a.out
2.3 两个函数
src = $(wildcard ./*.c): 匹配当前工作目录下的所有.c 文件。将文件名组成列表,赋给变量 src。
obj = $(patsubst %.c, %.o, $(src)): 将参数 3 中,包含参数 1 的部分,替换为参数 2
2.4 三个自动变量
$@: 在规则的命令中,表示规则中的目标
$^: 在规则的命令中,表示所有依赖条件。如果将该变量用在模式规则中,它可以将依赖条列表中的依赖依次取出,套用模式规则
$<: 在规则的命令中,表示第一个依赖条件。如果将该变量应用在模式规则中,它可将依条件列表中的依赖依次取出,套用模式规则
模式规则:
%.o:%.c
gcc -c $< -o %@
静态模式规则:
$(obj):%.o:%.c
gcc -c $< -o %@
两点注意:
-
目标的时间必须晚于依赖条件的时间,否则,更新目标
-
依赖条件如果不存在,找寻新的规则去产生依赖条件
-
ALL:指定 makefile 的终极目标
-
clean:
clean:
-rm -rf $(obj) a.out
-:作用是删除不存在文件时,不报错。顺序执行结束
- 伪目标:
.PHONY: clean ALL - 参数:
-n:模拟执行 make、make clean 命令
-f:指定文件执行 make 命令
三、使用
问题:
编写一个makefile实现自动编译。要求所有 .c 文件都放在 src 目录下,所有 .o 文件都放在 obj 目录下,所有头文件都放在 include 目录下,编译时加入-Wall 和 -g 参数,能够使用 make clean 指令删除 所有 .o 文件和主程序。
C文件:
main.c
#include <stdio.h>
#include "mymath.h"
int main()
{
int a = 10;
int b = 5;
printf("a + b = %d\n", add(a, b));
printf("a - b = %d\n", minus(a, b));
printf("a / b = %d\n", div(a, b));
return 0;
}
add.c
int add(int a, int b) {
return a + b;
minus.c
int minus(int a, int b) {
return a - b;
div.c
int div(int a, int b) {
return a / b;
}
头文件:
#ifndef _MYMATH_H
#define _MYMATH_H
int add(int , int );
int minus(int , int );
int div(int , int );
#endif
答案:
src = $(wildcard ./src/*.c)
obj = $(patsubst ./src/%.c, ./obj/%.o, $(src))
args = -Wall -g
inc_path = ./include
ALL:a.out
a.out:$(obj)
gcc $^ -o $@ $(args)
$(obj):./obj/%.o:./src/%.c
gcc $^ -c -o $@ -I $(inc_path)
clean:
-rm -rf $(obj) a.out
.PHONY: clean ALL
c/c++混合编译
编译目标:编译指定目录下文件(test目录不加入编译范围),编译生成可执行文件和动态库
# 编译目标
APPNAME := main
LIBNAME := libcode.so
TARGET := $(APPNAME)
all : $(LIBNAME) $(TARGET)
# 编译器
CC := gcc
CXX := g++
# 编译器参数
CFLAGS := -Wall -g -fPIC
CPPFLAGS := -Wall -lstdc++ -g -lc -fPIC
# 分别生成.c和.cpp文件列表
CFILES += $(wildcard src/div/*.c)
CFILES += $(wildcard src/minus/*.c)
CFILES += $(wildcard plugins/*.c)
CPPFILES += $(wildcard src/div/*.cpp)
CPPFILES += $(wildcard src/minus/*.cpp)
CPPFILES += $(wildcard plugins/*.cpp)
# .h头文件列表
HEADDIRS := ./include/ ./src/div/ ./src/minus ./plugins
INCS := $(addprefix -I, $(HEADDIRS))
# 程序所链接的库
LIBS := -lpthread
# .c生成.o文件列表
COBJS := $(patsubst %.c, %.o, $(CFILES))
CPPOBJS := $(patsubst %.cpp, %.o, $(CPPFILES))
# 生成动态库或静态库依赖列表
LIBOBJS += $(COBJS)
LIBOBJS += $(CPPOBJS)
# COBJS 和 CPPOBJS 用于生成动态库或静态库,应当不包含main.cpp/main.c, 避免符号冲突
APPOBJS += main.o
APPOBJS += $(COBJS)
APPOBJS += $(CPPOBJS)
# 编译
$(LIBNAME) : $(LIBOBJS)
@echo "\n###################### 编译动态库 ######################"
$(CXX) -shared -o $@ $^ -fPIC
@echo
$(TARGET) : $(APPOBJS)
@echo "\n###################### 编译TARGET ######################"
$(CXX) -o $@ $^ $(CPPFLAGS) $(LIBS)
main.o : ./src/main.cpp
$(CXX) -c $< -o $@ $(INCS) $(CPPFLAGS) $(LIBS)
$(COBJS) : %.o : %.c
$(CC) -c $< -o $@ $(INCS) $(CFLAGS) $(LIBS)
$(CPPOBJS) : %.o : %.cpp
$(CXX) -c $< -o $@ $(INCS) $(CPPFLAGS) $(LIBS)
# 清除编译文件
clean:
rm -rf $(APPOBJS) $(LIBNAME) $(TARGET)
# 伪文件
.PHONY : clean all