Linux 下 Makefile 模板
写个模板到处套,随便套,呵呵~~
变量名 | 含义 | 默认值 |
AR | 生成静态库库文件的程序名称 | ar |
AS | 汇编编译器的名称 | as |
CC | C语言编译器的名称 | cc |
CPP | C语言预编译器的名称 | $(CC) -E |
CXX | C++语言编译器的名称 | g++ |
FC | FORTRAN语言编译器的名称 | f77 |
RM | 删除文件程序的名称 | rm -f |
ARFLAGS | 生成静态库库文件程序的选项 | 无 |
ASFLAGS | 汇编语言编译器的编译选项 | 无 |
CFLAGS | C语言编译器的编译选项 | 无 |
CPPFLAGS | C语言预编译的编译选项 | 无 |
CXXFLAGS | C++语言编译器的编译选项 | 无 |
FFLAGS | FORTRAN语言编译器的编译选项 | 无 |
变量 | 含义 |
$* | 表示目标文件的名称,不包含目标文件的扩展名 |
$+ | 表示所有的依赖文件,这些依赖文件之间以空格分开,按照出现的先后顺序,其中可能包含重复的依赖文件 |
$< | 表示依赖项中第一个依赖文件的名称 |
$? | 依赖项目中,所有目标文件时间戳晚的依赖文件,依赖文件之间以空格分开 |
$@ | 目标项目中目标文件的名称 |
$^ | 依赖项中,所有不重复的依赖文件,这些文件之间以空格分开 |
文件目录结构如下:
注意:add_a和sub_b目录下的Makefile为编译多个Makefile时使用
1、五个代码文件如下
main.c文件
#include <stdio.h>
#include "add.h"
#include "sub.h"
int main(int argc, char const *argv[])
{
int a=7,b=5;
printf("%d+%d=%d\n",a,b,add(a,b));
printf("%d-%d=%d\n",a,b,sub(a,b));
return 0;
}
add.c文件
#include "add.h"
int add(int a,int b)
{
return (a+b);
}
add.h文件
#ifndef ADD_H
#define ADD_H
#include <stdio.h>
int add(int a,int b);
#endif
sub.c文件
#include "sub.h"
int sub(int a,int b)
{
return (a-b);
}
sub.h文件
#ifndef SUB_H
#define SUB_H
#include <stdio.h>
int sub(int a,int b);
#endif
2、Makefile文件如下
模板1:没有 *.o 文件的生成
TOP_DIR := $(shell pwd)
DEP_LIBS = \
-I./add_a \
-I./sub_a
OBJS = \
add_a/add.c \
sub_a/sub.c \
main.c
CC = gcc
CFLAGS = -Wall -O -g
#-Wall:输出所有的警告信息。
#-O:在编译时进行优化。
#-g:表示编译debug版本。
out: $(OBJS)
$(CC) $(CFLAGS) -o out $(OBJS) $(DEP_LIBS) -L$(TOP_DIR)
.PHONY:clean
clean:
rm -f *.o out
模板2:有 *.o 文件的生成
CC=gcc
out:add.o sub.o main.o
$(CC) -o out add_a/add.o sub_a/sub.o main.o
add.o:add_a/add.c add_a/add.h
$(CC) -c -o add_a/add.o add_a/add.c
sub.o:sub_a/sub.c sub_a/sub.h
$(CC) -c -o sub_a/sub.o sub_a/sub.c
main.o:main.c add_a/add.h sub_a/sub.h
$(CC) -c -o main.o main.c -Iadd_a -Isub_a
.PHONY:clean
clean:
rm -f *.o add/*.o sub/*.o out
模板3:有 *.o 文件的生成
CC = gcc
#加入头文件搜索路径 O2为优化
CFLAGS = -Isub_a -Iadd_a -O2
OBJS = add_a/add.o sub_a/sub.o main.o
#最终生成的目标
TARGET = out
RM = rm -f
$(TARGET):$(OBJS)
$(CC) -o $(TARGET) $(OBJS) $(CFLAGS)
#将 OBJS 中所有扩展名为 .o 的文件替换成扩展名为.c的文件
$(OBJS):%.o:%.c
$(CC) -c $(CFLAGS) $< -o $@
clean:
-$(RM) $(TARGET) $(OBJS)
模板4:自动搜索文件路径
CC = gcc
#加入头文件搜索路径 O2为优化
CFLAGS = -Iadd_a -Isub_a -O2
OBJSDIR = .OBJS
VPATH = add_a:sub_a:.
OBJS = add.o sub.o main.o
#最终生成的目标
TARGET = out
RM = rm -f
$(TARGET):$(OBJSDIR) $(OBJS)
$(CC) -o $(TARGET) $(OBJSDIR)/*.o $(CFLAGS)
#将 OBJS 中所有扩展名为 .o 的文件替换成扩展名为.c的文件
$(OBJS):%.o:%.c
$(CC) -c $(CFLAGS) $< -o $(OBJSDIR)/$@
$(OBJSDIR):
mkdir -p ./$@
clean:
-$(RM) $(TARGET)
-$(RM) $(OBJSDIR)/*.o
模板5:自动推导过程
CFLAGS = -Iadd_a -Isub_a -O2
VPATH = add_a:sub_a
OBJS = add.o sub.o main.o
TARGET = out
CC = gcc
$(TARGET):$(OBJS)
$(CC) -o $(TARGET) $(OBJS) $(CFLAGS)
clean:
-$(RM) $(TARGET)
-$(RM) $(OBJS)
模板6:递归调用的方式(编译多个Makefile用)
#总Makefile
CC = gcc
CFLAGS = -O2
TARGET = out
#生成当前目录的路径字符串,并赋值给OBJSDIR,外部可调用
export OBJSDIR = $(shell pwd)/.objs
$(TARGET):$(OBJSDIR) main.o
#等同于 cd add && $(MAKE) ,在目录add中递归调用make
$(MAKE) -C add_a
$(MAKE) -C sub_a
#生成的 main.o 放到OBJSDIR里面去
$(CC) -o $(TARGET) $(OBJSDIR)/*.o
main.o:%.o:%.c
$(CC) -c $< -o $(OBJSDIR)/$@ $(CFLAGS) -Iadd_a -Isub_a
$(OBJSDIR):
mkdir -p $(OBJSDIR)
clean:
-$(RM) $(TARGET)
-$(RM) $(OBJSDIR)/*.o
add_a目录下的Makefile
OBJS = add.o
all:$(OBJS)
$(OBJS):%.o:%.c
#CC 和OBJSDIR在总控Mkirfile声明
$(CC) -c $< -o $(OBJSDIR)/$@ $(CFLAGS)
clean:
$(RM) $(OBJS)
sub_a目录下的Makefile
OBJS = sub.o
all:$(OBJS)
$(OBJS):%.o:%.c
#CC 和OBJSDIR在总控Mkirfile声明
$(CC) -c $< -o $(OBJSDIR)/$@ $(CFLAGS)
clean:
$(RM) $(OBJS)
模板7:模式替换函数 patsubst
CC = gcc -g
CFLAGS = -Iadd_a -Isub_a -O2
TARGET = out
#DIRS字符串的值为目录add_a sub_a 和当前目录
DIRS = sub_a add_a .
#查询说用目录下的扩展名为.c的文件,赋值给变量FILES
FILES = $(foreach dir, $(DIRS),$(wildcard $(dir)/*.c))
OBJS = $(patsubst %.c,%.o,$(FILES))
$(TARGET):$(OBJS)
$(CC) -o $(TARGET) $(OBJS)
clean:
-$(RM) $(TARGET)
-$(RM) $(OBJS)