元素星在线活动查询中心

元素星在线活动查询中心

shape
  • Home
  • 活动查询
  • Makefile入门

Makefile入门

  • 2025-10-03 20:08:45
  • admin

# 一、Makefile简介# 1、Makefile是什么Makefile是一种用于自动化构建程序的工具,它提供了一系列规则来指定源代码文件之间的依赖关系,以及如何生成目标文件。通过使用Makefile,程序员可以有效地管理和组织软件项目的编译过程,从而提高开发效率。

Makefile文件是一个文本文件,其中包含一系列规则和指令,用于编译源代码并生成可执行文件或库。每个规则由一个目标文件、一个或多个依赖文件和一组命令组成,这些命令描述了如何从依赖文件生成目标文件。

Makefile的主要作用是简化或组织编译代码的过程,它可以帮助程序员自动化编译、链接和打包程序。通过将整个项目分解为多个模块,并定义每个模块之间的依赖关系,当某个模块发生变化时,只需要重新编译该模块及其依赖的其他模块即可。这有助于减少手动操作和错误,并提高代码质量。

此外,Makefile还支持变量定义和隐晦规则等特性,这些特性可以帮助程序员更加灵活地编写Makefile,并使构建过程更加易于维护和扩展。

# 2、make 和 Makefile的关系Make是一个命令工具,用于解释和执行Makefile中的指令,完成项目的自动化构建。Makefile是一个文件,其中定义了一系列的规则来指定哪些文件需要先编译、哪些文件需要后编译、哪些文件需要重新编译等。

当我们在命令行中输入make命令时,Make会查找当前目录下是否存在名为Makefile或makefile的文件。如果找到,Make会按照Makefile文件中的规则和指令,自动执行相应的命令来编译和链接源代码文件,生成可执行文件或库。

# 二、Makefile 三要素Makefile的三个要素是目标、依赖和命令。它们在Makefile中的格式如下:

目标(Target):目标是指需要生成的文件或目标体,可以是Object File(一般称为中间文件)、可执行文件或标签。目标定义了生成的目标体,并指明生成目标体需要哪些依赖文件。

依赖(Dependency):依赖是指生成目标体所需的文件或另一个目标。它可以是一个或多个文件,也可以没有。依赖项描述了目标文件与源文件之间的依赖关系,告诉Make如何从源文件生成目标文件。

命令(Command):命令是Make需要执行的命令行指令,可以是任意的shell命令。这些命令描述了如何从依赖文件生成目标文件。在Makefile中,命令部分需要有一定的缩进,可以是一行或多行,它们会依次执行。

以下是Makefile三要素的格式示例:

代码语言:javascript代码运行次数:0运行复制目标: 依赖

命令其中,目标和依赖之间用冒号(:)分隔,命令部分需要缩进。

示例:

代码语言:javascript代码运行次数:0运行复制# vim Makefile

targeta:targetb targetc

echo "targeta"

targetb:

echo "targetb"

targetc:

echo "targetc"执行make命令

代码语言:javascript代码运行次数:0运行复制# make

echo "targetb"

targetb

echo "targetc"

targetc

echo "targeta"

targeta指定执行命令

代码语言:javascript代码运行次数:0运行复制# make targetb

echo "targetb"

targetb

# touch targetb

# make targetb # 当前目录下targetb是最新文件不需要改变

make: `targetb' is up to date.修改Makefile文件

代码语言:javascript代码运行次数:0运行复制# vim Makefile

.PHONY:targetb

targeta:targetb targetc

echo "targeta"

targetb:

echo "targetb"

targetc:

echo "targetc"

# make targetb

echo "targetb"

targetb .PHONY:targetb的意思是声明``targetb是一个伪目标,即使存在名为targetb的文件。这意味着,每次当你运行make targetb时,make不会尝试查找一个叫做targetb的文件并尝试运行它的命令,而是会执行与targetb` 关联的命令。

在这个例子中,如果你运行 make targetb,它会输出 "targetb"。如果你运行 make targeta,它会首先运行 targetb 和 targetc 的命令,然后执行与 targeta 关联的命令,输出 "targeta"。

# 三、引入Makefile管理项目生成两个文件

代码语言:javascript代码运行次数:0运行复制# vim mp3.c

#include

void play()

{

printf("paly music!\r\n");

}

void stop()

{

printf("stop music!\r\n");

}

# vim main.c

#include

int main()

{

play();

stop();

return 0;

}编写Makefile

代码语言:javascript代码运行次数:0运行复制# vim Makefile

mq3:main.c mp3.c

gcc main.c mp3.c -o mp3

.PHONE:clean

clean:

rm mp3

# make

# ls

main.c Makefile mp3 mp3.c

# ./mp3

paly music!

stop music!改造Makefile,目的是将mp3.c和main.c解耦,当修改mp3.c或者main.c时,不需要重新编译另一个文件

代码语言:javascript代码运行次数:0运行复制# vim Makefile

mq3:main.o mp3.o

gcc main.o mp3.o -o mp3

main.o:

gcc -c main.c -o main.o

mp3.o:

gcc -c mp3.c -o mp3.o

.PHONE:clean

clean:

rm mp3

# make clean

rm mp3

# make

# ./mp3

paly music!

stop music!# 四、Makefile的变量和模式匹配# 1、系统变量代码语言:javascript代码运行次数:0运行复制# vim Makefile

.PHONY:all

all:

echo "${CC}"

echo "${AS}"

echo "${MAKE}"

echo "${PATH}"

# make

echo "cc"

cc

echo "as"

as

echo "make"

make

echo "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin"

/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin# 2、自定义变量1、延迟赋值

在Makefile中,变量的默认赋值方式是“延迟”的。这意味着变量只有在被引用时才会被计算,并且只计算一次。如果一个变量在多个地方被引用,那么只有第一次引用时会被计算,后续的引用会使用第一次计算的结果。

代码语言:javascript代码运行次数:0运行复制# vim Makefile

A=123

B=$(A)

A=456

.PHONY:all

all:

echo "${B}"

# make

echo "456"

4562、立即赋值

为了改变默认的延迟赋值行为,我们可以使用:=操作符进行“立即”赋值。这意味着变量会在声明时立即被计算,并且在之后的所有引用中都会使用这个计算结果。即使变量的值在后续发生了变化,之前的引用也不会受到影响。

代码语言:javascript代码运行次数:0运行复制# vim Makefile

A=123

B:=$(A)

A=456

.PHONY:all

all:

echo "${B}"

# make

echo "123"

123 3、空赋值

使用=操作符可以将变量设置为空字符串。这在需要临时清除变量的内容时很有用。

代码语言:javascript代码运行次数:0运行复制# vim Makefile

A?=123

#B:=$(A)

A?=456

.PHONY:all

all:

echo "${A}"

# make

echo "123"

123 4、追加赋值

如果想要将一个值追加到变量的末尾,可以使用+=操作符。这不会覆盖变量的现有内容,而是将新值添加到变量的末尾。

代码语言:javascript代码运行次数:0运行复制# vim Makefile

A?=123

#B:=$(A)

A+=456

.PHONY:all

all:

echo "${A}"

# make

echo "123 456"

123 456# 3、自动化变量1、$<

代表第一个依赖项。在规则的命令部分,$<将被替换为第一个依赖项的文件名。

代码语言:javascript代码运行次数:0运行复制# vim Makefile

all:targeta targetb

echo "$<"

targeta:

targetb:

# make

echo "targeta"

targeta2、$^

代表所有的依赖项。在规则的命令部分,$^将被替换为一个空格分隔的列表,包含了所有依赖项的文件名

代码语言:javascript代码运行次数:0运行复制# vim Makefile

all:targeta targetb

echo "$^"

targeta:

targetb:

# make

echo "targeta targetb"

targeta targetb3、$@

代表目标文件。在规则的命令部分,$@将被替换为目标文件的名字。

代码语言:javascript代码运行次数:0运行复制# vim Makefile

all:targeta targetb

echo "$@"

targeta:

targetb:

# make

echo "all"

all# 4、变量使用代码语言:javascript代码运行次数:0运行复制# vim Makefile

CC=gcc

TARGET=mp3

OBJS=main.o mp3.o

$(TARGET):$(OBJS)

$(CC) $^ -o $@

main.o:main.c

$(CC) -c main.c -o main.o

mp3.o:mp3.c

$(CC) -c mp3.c -o mp3.o

.PHONY:clean

clean:

rm mp3

# make

gcc main.o mp3.o -o mp3

# ./mp3

paly music!

stop music!# 5、模式匹配%:匹配任意多个非空字符

代码语言:javascript代码运行次数:0运行复制# vim Makefile

%:

echo "$@"

# make test # make后跟任意字符

echo "test"

test优化Makefile

代码语言:javascript代码运行次数:0运行复制# vim Makefile

CC=gcc

TARGET=mp3

OBJS=main.o mp3.o

$(TARGET):$(OBJS)

$(CC) $^ -o $@

# 因为.o文件默认使用.c文件来进行编译,所以可以注释以下两行

#%.o:%.c

# ${CC} -c $< -o $@

.PHONY:clean

clean:

rm mp3

# make

gcc main.o mp3.o -o mp3

# ./mp3

paly music!

stop music!# 五、Makefile的条件分支代码语言:javascript代码运行次数:0运行复制# vim Makefile

ARCH ?= x86

ifeq ($(ARCH),x86)

CC=gcc

else

CC=arm-linux-gnueabihf-gcc

endif

TARGET=mp3

OBJS=main.o mp3.o

$(TARGET):$(OBJS)

$(CC) $^ -o $@

.PHONY:clean

clean:

rm mp3 *.o

# make

gcc -c -o mp3.o mp3.c

gcc main.o mp3.o -o mp3

# make ARCH=arm

arm-linux-gnueabihf-gcc -c -o mp3.o mp3.c

arm-linux-gnueabihf-gcc main.o mp3.o -o mp3# 六、Makefile管理Docker# 1、创建一个Dockerfile代码语言:javascript代码运行次数:0运行复制FROM nginx

RUN echo '

Hello World!

' > /usr/share/nginx/html/index.html# 2、创建Makefile文件代码语言:javascript代码运行次数:0运行复制# 定义 Docker 镜像名称和标签

REGISTRY := your-private-registry

USERNAME := your-username

PASSWORD := your-password

TAG := latest

IMAGE := my-web

# 这是一个条件赋值。如果变量 CONTAINER_NAME 还没有被赋值,那么它会被赋值为 my-container

CONTAINER_NAME ?= my-container

# 构建镜像

build: docker-build

docker build -t $(IMAGE):$(TAG) .

# 上传镜像到私有仓库

upload: docker-push

docker login -u $(USERNAME) -p $(PASSWORD) $(REGISTRY)

docker push $(IMAGE):$(TAG)

# 运行镜像

run: docker-run

docker run -p 80:80 $(CONTAINER_NAME) $(IMAGE):$(TAG)

# 停止并删除容器

clean: docker-stop docker-rm

docker stop $(CONTAINER_NAME)

docker rm $(CONTAINER_NAME) # 3、执行命令代码语言:javascript代码运行次数:0运行复制# make build

# make upload

# make run

# make clean

Previous Post
【更改 Apple ID 終極指南】這裡有 Apple ID 更改的所有詳細資訊
Copyright © 2088 元素星在线活动查询中心 All Rights Reserved.
友情链接