linux c编程之Makefile使用

本文详细介绍Makefile的基础概念及其在实际项目中的应用。包括Makefile的基本语法、自动化变量、内嵌函数以及多级目录下的Makefile编写技巧。通过具体示例展示了如何通过Makefile简化编译流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

make工具通过一个称为Makefile的文件来完成并自动维护编译工作。
Makefile文件描述了整个工程的编译、链接等规则。

Target… : DEPENDENCIES…
COMMAND

目标:程序产生的文件,如可执行文件和目标文件;目标也可以是可执行的动作,如clean,也称作伪目标。
依赖:是用来产生目标的输入文件列表,一个目标通常依赖于多个文件。
命令:是make执行的动作(命令是shell命令或是可在shell下执行的程序)。注意:每个命令行的起始字符必须为TAB字符!
如果依赖文件列表DEPENDENCIES中有一个或多个文件更新的话,COMMAND就要执行,这就是Makefile最核心内容。

例子

假设当前目录下有main.c add.c sub.c add.h sub.h等文件,欲生成main可执行文件,则Makefile可以这么写:
注意命令行起始必须是TAB字符!!!

第一版

main:main.o add.o sub.o
 gcc -Wall -g main.o add.o sub.o -o main
main.o:main.c
 gcc -Wall -g -c main.c -o main.o
add.o:add.c add.h
 gcc -Wall -g -c add.c -o add.o
sub.o:sub.c sub.h
 gcc -Wall -g -c sub.c -o sub.o
clean:
 rm -rf main main.o add.o sub.o

第一版存在的主要问题在于如果当前目录下有名称为clean的文件,则make clean时就会出现问题。

第二版

第二版就是为了改进第一版存在的问题(显式指定伪目标)

.PHONY:clean
main:main.o add.o sub.o
 gcc -Wall -g main.o add.o sub.o -o main
main.o:main.c
 gcc -Wall -g -c main.c -o main.o
add.o:add.c add.h
 gcc -Wall -g -c add.c -o add.o
sub.o:sub.c sub.h
 gcc -Wall -g -c sub.c -o sub.o
clean:
 rm -rf main main.o add.o sub.o

如果不想在编译时显示编译命令,则在command前加入@符号

Makefile的自动化变量

  • $@:规则的目标文件名
  • $<:规则的第一个依赖文件名
  • $^:规则的所有依赖文件列表

第三版

第三版主要是为了定义一些变量,让这个Makefile更为通用,少敲一些代码。ps:在Makefile中变量引用使用$(变量)这种方式。

.PHONY:clean
OBJECTS=main.o add.o sub.o
main:$(OBJECTS)
 gcc -Wall -g $^ -o $@
main.o:main.c
 gcc -Wall -g -c $< -o $@
add.o:add.c add.h
 gcc -Wall -g -c $< -o $@
sub.o:sub.c sub.h
 gcc -Wall -g -c $< -o $@
clean:
 rm -rf main $(OBJECTS)

如何在当前目录下生成多个可执行文件

模式规则
%.o:%.c
后缀规则
.c.o:
(当前文件夹下.o文件对应着.c文件)

第一版

.PHONY:clean all
BIN=01test 02test
all:$(BIN)
#%.o:%.c
 #gcc -Wall -g -c $< -o $@
.c.o:
 gcc -Wall -g -c $< -o $@
01test:01test.o
 gcc -Wall -g  $^ -o $@
02test:02test.o
 gcc -Wall -g  $^ -o $@
clean:
 rm -rf *.o $(BIN)

生成过程:生成all->生成BIN->生成01test和02test

第二版

.PHONY:clean all
CC=gcc
CFLAGS=-Wall -g
BIN=01test 02test
all:$(BIN)
#%.o:%.c(当前文件夹下.o文件对应着.c文件)
 #$(CC) $(CFLAGS) -c $< -o $@
.c.o:
 $(CC) $(CFLAGS) -c $< -o $@
01test:01test.o
 $(CC) $(CFLAGS)  $^ -o $@
02test:02test.o
 $(CC) $(CFLAGS)  $^ -o $@
clean:
 rm -rf *.o $(BIN)

第三版

增加一个可执行文件03test,其依赖项03test.o abc.o

.PHONY:clean all
CC=gcc
CFLAGS=-Wall -g
BIN=01test 02test 03test
all:$(BIN)
#%.o:%.c(当前文件夹下.o文件对应着.c文件)
 #$(CC) $(CFLAGS) -c $< -o $@
.c.o:
 $(CC) $(CFLAGS) -c $< -o $@
01test:01test.o
 $(CC) $(CFLAGS)  $^ -o $@
02test:02test.o
 $(CC) $(CFLAGS)  $^ -o $@
03test:03test.o abc.o
 $(CC) $(CFLAGS)  $^ -o $@
clean:
 rm -rf *.o $(BIN)

再增加一个可执行文件04test

.PHONY:clean all
CC=gcc
CFLAGS=-Wall -g
BIN=01test 02test 03test 04test
all:$(BIN)
#%.o:%.c(当前文件夹下.o文件对应着.c文件)
 #$(CC) $(CFLAGS) -c $< -o $@
.c.o:
 $(CC) $(CFLAGS) -c $< -o $@
01test:01test.o
 $(CC) $(CFLAGS)  $^ -o $@
02test:02test.o
 $(CC) $(CFLAGS)  $^ -o $@
03test:03test.o pub.o
 $(CC) $(CFLAGS)  $^ -o $@
clean:
 rm -rf *.o $(BIN)>

make常用内嵌函数

函数调用

$(function arguments)

$(Wildcard PATTERN)

当前目录下匹配模式的文件
src=$(wildcard *.c)

$(patsubst PATTREN,REPLACEMENT,TEXT)

模式替换函数
(patsubst src)/将src里的.c后缀文件替换为.o/
等价于$(src:.c=.o)

shell函数

执行shell命令
$(shell ls -d */)

多级目录的Makefile

所有目录只有一个可执行文件

**以下的Makefile适合当前目录存放main.c,子目录add/和sub/分别存放了main.c里用到的add和sub函数声明及定义add.c add.h sub.c sub.h
这种情况**

CC=gcc
CFLAGS=-Wall -g
CINCLUDES=-I./add -I./sub
BIN=main
SUBDIR=$(shell ls -d */)
ROOTSRC=$(wildcard *.c)
ROOTOBJ=$(ROOTSRC:%.c=%.o)
SUBSRC=$(shell find $(SUBDIR) -name '*.c')
SUBOBJ=$(SUBSRC:%.c=%.o)
$(BIN):$(ROOTOBJ) $(SUBOBJ)
 $(CC) $(CFLAGS) -o $(BIN) $(ROOTOBJ) $(SUBOBJ)
.c.o:
 $(CC) $(CFLAGS) $(CINCLUDES) -c $< -o $@
clean:
 rm -rf $(BIN) $(ROOTOBJ) $(SUBOBJ)

每个目录都可生成可执行文件

前提是想生成可执行文件的目录下有对应的Makefile

当前目录

SUBDIRS=test1 test2
.PHONY:default all clean $(SUBDIRS)
default:all
all clean:
 $(MAKE) $(SUBDIRS) TARGET=$@     
$(SUBDIRS):
 $(MAKE) -C $@ $(TARGET)

$(MAKE) ==make

子目录

test1子目录下Makefile

CC=gcc
BIN=test1
OBJS=test1.o
.PHONY:all clean print
all:print $(BIN)
print:
 @echo "---make all in $(PWD)---"
$(BIN):$(OBJS)
 $(CC) $(OBJS) -o $@
.c.o:
 $(CC) -c $<
clean:
 @echo "---make clean in $(PWD)---"
 rm -rf $(BIN) $(OBJS)

test2子目录下Makefile

CC=gcc
BIN=test2
OBJS=test2.o
.PHONY:all clean print
all:print $(BIN)
print:
 @echo "---make all in $(PWD)---"
$(BIN):$(OBJS)
 $(CC) $(OBJS) -o $@
.c.o:
 $(CC) -c $<
clean:
 @echo "---make clean in $(PWD)---"
 rm -rf $(BIN) $(OBJS)>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值