makefile工具

本文深入解析Makefile的原理与应用,从基础规则到高级特性,涵盖自动化变量、模式规则及多级目录编译策略。通过实例演示如何高效管理大型项目编译流程,提升软件开发效率。

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

简介

1)make:利用 make 工具可以自动完成编译工作。这些工作包括:如果仅修改了某几个源文件,则只重新编译这几个源文件[make通过比对相应的.c文件与.o文件的时间];如果某个头文件被修改了,则重新编译所有包含该头文件的源文件。利用这种自动编译可大大简化开发工作,避免不必要的重新编译。

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

 

Mackfile基本规则

Target ...: Dependencies ...

Command ...

 

说明:

1)目标(TARGET):即最终想要产生的文件,如:可执行文件,目标文件或中间文件等;目标也可以是要执行的动作,如clean,也称为伪目标。

2)依赖(DEPENDENCIES):为了产生目标文件而依赖的文件列表,一个目标通常依赖于多个文件。

3)命令(COMMAND):是make执行的动作(shell命令或是可在shell下执行的程序,如echo)。注意:每个命令行的起始字符必须为TAB字符!

如果DEPENDENCIES中有一个或多个文件更新的话,COMMAND就要执行,这就是Makefile最核心的内容.

 

简单的Mackfile示例

 

#1 最简单

hello:

gcc -o hello hello.c

 

#2 稍微复杂

hello:hello.o

gcc -o hello hello.o

 

hello.o:

gcc -o hello.o -c hello.c

 

#3 进一步完善

hello:hello.o

gcc -o hello hello.o

 

hello.o:

gcc -o hello.o -c hello.c

 

clean:

rm -rf hello.o  #delete file hello.o

 

#4 在Mackfile中执行shell命令[@符号:不输出命令本身]

hello:hello.o

gcc -o hello hello.o

@echo "--------------ok------------"

 

hello.o:

gcc -o hello.o -c hello.c

 

clean:

rm -rf hello.o  #delete file hello.o

 

#5 综合[.PHONY:#显示声明伪目标]

.PHONY: clean

main: main.o sub.o add.o

gcc -Wall -g -o main main.o sub.o add.o

 

main.o: main.c

gcc -Wall -g -o main.o -c main.c

 

add.o: add.c add.h

gcc -Wall -g -o add.o -c add.c

 

sub.o: sub.c sub.h

gcc -Wall -g -o sub.o -c sub.c

 

clean:

rm -f main.o sub.o add.o

 

执行:

1)make #生成第一个目标

2)make clean #“生成”clean伪目标

3)make main.o #仅生成main.o目标

4)make -f Mackfile #显示指定执行的文件名

5).PHONY:clean   显示指定伪目标

 

Makefile变量

为了简化和维护Mackfile,可以在Mackfile中使用变量,格式

varname=some_text

引用变量的值:$(varname)

按照惯例,在Mackfile中,变量一般大写

 

 

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 -f main $(OBJECTS)

 

 

Make使用隐含推导规则/生成多个可执行文件

#示例-生成多个可执行文件1  可将test1.c 和test2.c生成可执行文件  

.PHONY: clean all 

BIN = 01test 02test

all: $(BIN)

clean:

    -rm -f $(BIN)

以上隐含了自动推导

 

#示例-生成多个可执行文件2-使用自己定制的规则,生成.o中间文件

.PHONY: clean all 

BIN = 01test 02test

all: $(BIN)

01test.o: 01test.c

   gcc  -Wall -g  $^   -o   $@

02test.o: 02test.c

   gcc  -Wall  -g  $^   -o  $@

clean:

-rm -f $(BIN) 

 

 

 

模式规则与后缀规则

%.o:%.c

.c.o:

 

#示例

.PHONY: clean all 

CC = gcc 

CFLAGS = -Wall -g

BIN = 01test 02test 

all: $(BIN)

#%.o: %.c #模式规则

#   $(CC) $(CFLAGS)   -c   $<   -o    $@

.c.o: #后缀规则,与前作用相同

    $(CC) $(CFLAGS)   -c    $<    -o   $@

01test:01test.0

     $(CC)  $(CFLAGS)   $^  -o   $@

02test:02test.0

    $(CC)   $(CFLAGS)  $^   -o   $@

clean:

    -rm -rf   *.o  $(BIN)

 

make常用内嵌函数

1、函数调用

   $(function arguments)         #$引用的结果就是函数生成的结果

2、Makefile下常用的函数

1)$(wildcard PATTERN) #匹配当前目录下的文件

例如:src=$(wildcard *.c) #匹配当前目录下所有的.c文件

2)$(patsubst PATTERN,REPLACEMENT,TEXT) #模式替换函数

例如:$(patsubst %.c,%.o,$src) #等价于$(src:%.c=%.o)[常用]

3)shell函数,执行shell命令

例如:$(shell ls –d */)

 

多级目录Makefile

#示例1-所有的编译均由主目录下的Makefile完成

CC = gcc   

CFLAGS   = -Wall -g

BIN      = main  

SUBDIR   = $(shell ls -d */) #SUBDIR保存了当前目录下的子目录
ROOTSRC  = $(wildcard *.c) #ROOTSRC保存了当前目录下的.c文件
ROOTOBJ  = $(ROOTSRC:%.c=%.o) #ROOTOBJ保存了将ROOTSRC中.c替换为.o文件之后的结果

SUBSRC   = $(shell find $(SUBDIR) -name '*.c') #SUBSRC保存了所有子目录下的所有.c文件
SUBOBJ   = $(SUBSRC:%.c=%.o) #SUBOBJ保存了将SUBSRC中.c替换为.o文件之后的结果

$(BIN):$(ROOTOBJ) $(SUBOBJ)
        $(CC) $(CFLAGS) -o $(BIN) $(ROOTOBJ) $(SUBOBJ)
%.o:%.c
        $(CC) $(CFLAGS) -c $< -o $@ #将所有的.c生成.o文件
clean:
        rm -f $(BIN) $(ROOTOBJ) $(SUBOBJ)

 

 

 

生成分布在多个目录下的可执行文件

#每个子目录都需要生成一个可执行文件,每个目录下都有makefile文件

 

#各个文件的内容如下

//test1/test1.c

#include <stdio.h>
int main()
{
printf("Hello !\n");
return 0;
}

 

 

#test1/Makefile 
.PHONY: all clean print
CC = gcc 
CFLAGS = -Wall -g


BIN = test1
SOURCES = $(wildcard *.c)
OBJECTS = $(SOURCES:%.c=%.o)


all: print $(BIN)
print:
    @echo "----- make all in $(PWD) -----"

$(BIN): $(OBJECTS)
     $(CC) $(CFLAGS) -o $@ $^

#$(OBJECTS): $(SOURCES)
%.o: %.c 
    $(CC) $(CFLAGS) -o $@ -c $<



clean:
    @echo "---- make clean in $(PWD) -----"
    -rm -rf $(BIN) $(OBJECTS)

 

//test2/test2.cpp
#include <iostream>
using namespace std;
int main(void)
{
cout << "World!" << endl;
}
#test2/Makefile

.PHONY: clean all print
CXX = g++ 
CPPFLAGS = -Wall -g

BIN = test2
SOURCES = $(wildcard *.cpp)
OBJECTS = $(SOURCES:.cpp=.o)

all: print $(BIN)
print:
    @echo "----- make all in $(PWD) -----"

$(BIN): $(OBJECTS)
    $(CXX) $(CPPFLAGS) -o $@ $<

%.o: %.cpp  #可以省略该行以及下面一行

    $(CXX) $(CPPFLAGS) -o $@ -c $<



clean:
    @echo "----- make clean in $(PWD) -----"
    -rm -rf $(BIN) $(OBJECTS)

 

#Makefile-在主目录下

SUBDIR = $(shell /bin/ls -d */)
.PHONY: default all clean $(SUBDIR)

default: all 
all clean:
    $(MAKE) $(SUBDIR) TARGET=$@

$(SUBDIR):
    $(MAKE) -C $@ $(TARGET)

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值