您的位置:首页 > 娱乐 > 明星 > 千图网素材下载网站_app免费下载大全_网站怎么创建_百度正式员工工资待遇

千图网素材下载网站_app免费下载大全_网站怎么创建_百度正式员工工资待遇

2025/3/17 15:24:35 来源:https://blog.csdn.net/2403_86653825/article/details/146191930  浏览:    关键词:千图网素材下载网站_app免费下载大全_网站怎么创建_百度正式员工工资待遇
千图网素材下载网站_app免费下载大全_网站怎么创建_百度正式员工工资待遇

1.背景介绍

linux中C语言可执行文件a.out的由来如下:

  • test.c经过预编译到test.i
  • test.i经过编译到test.s
  • test.s经过汇编到test.o
  • test.o经过链接到a.out

但是对于一个大型工程,每次生成新的可执行文件都要重新对每个文件(或者对修改了的文件)进行编译、链接等操作的工作量太大了。

因此提出就有了make/makefile,它是一个工程文件的编译链接规则,规则写好之后,只需要一个make就能生成可执行文件。

2.语法

2.1 语法格式

all: 目标文件1 目标文件2
目标文件1: 依赖文件1, 依赖文件2...
<tab>命令1
<tab>命令2...
目标文件2: 依赖文件1, 依赖文件2...
<tab>命令1
<tab>命令2...
  • 目标文件即要生成的文件,一半情况下makefile中的第一个目标文件为最终目标
  • 依赖文件:该文件由哪些文件生成
  • 命令:通过执行命令来由依赖文件生成目标文件。这里默认执行命令时会在终端输出命令的内容。如果在命令前加"@"符号,则终端隐藏命令,但是返回到标准输出的内容不会隐藏。
  • all:makefile文件默认只生成一个目标文件即完成编译。如果想要生成多个目标文件,则需要all并放在第一行列出所有的生成文件。

2.2 变量

2.2.1 自定义变量

变量定义:

  • 递归展开:VAR= var1 var2…多个值中间用空格隔开
  • 直接赋值:VAR:=var。

赋值操作:

  • “=”:使用"="进行赋值,变量的值是整个Makefile中最后被指定的值,例如:
VAR_A = A
VAR_B = $(VAR_A) B
VAR_A = AA

最后VIR_B的值为AA B而不是A B

  • “:=”:表示直接赋值,赋予当前位置的值
VAR_A := A
VAR_B := $(VAR_A) B
VAR_A := AA

最后VIR_B的值为A B

  • “?:”:表示如果该变量没有被赋值,则将后面的值赋给它
VAR ?= value

VAR的值为value

VAR := value1
VAR ?= value2

VAR的值为value1

  • “+=”:类似C语言,将右边的变量追加到左边的变量中。

“$“符号表示取变量的值,当变量名多于一个字符时,需要使用”()”

2.2.2 自动变量

  • “$^”: 表示所有的依赖文件,并以空格分开
  • “$@”: 表示生成的目标文件
  • “$<”: 代表第一个依赖文件
  • “$?”: 所有时间戳比目标文件晚的依赖文件,并以空格分开

2.2.3 预定义变量

  • CC:C编译器的名称,默认值为cc
  • RM:文件删除程序的名称,默认值为rm -f
  • CFLAGES:C编译器(gcc)的选项,默认无默认值,如-Wall、-g、-o
  • AR:库文件维护程序的名称,默认值为ar
  • CPP:C预编译器的名称,默认值为$(CC) -E
  • CPPFLAGS:C预编译器的选项,无默认值
  • CXXFLAGS:C++编译器(g++)的选项,无默认值

2.2.4 隐含变量

  • “%.o”: 任意的.o文件
  • “*.o”: 所有的.o文件

2.3 函数

2.3.1 名称处理函数

  1. wildcard
$(wildcard <pattern...>)

获取指定格式的文件列表
示例:

$(wildcard *.cpp test/*.cpp)

代表当前目录下所有的.cpp文件和test目录下所有的.cpp文件。

  1. dir
$(dir <names...>)

获取文件所在目录,本质上是获取最后一个"/“以前的内容,如果没有”/“,返回”./"
示例:

$(dir src/foo.c sum.txt)

返回"src/ ./"

  1. notdir
$(notdir <names...>)

获取一个文件路径的非目录不放呢,即获得文件名。本质上是获取最后一个反斜杠"/"之后的内容,如果没有反斜杠,则直接返回本身
示例:

$(notdir src/foo.c sum.txt)

返回"foo.c sum.txt"

  1. suffix
$(suffix <names...>)

获取文件的后缀,如果没有后缀,则返回空字符。本质是获取最后一个"."后面的内容
示例:

$(suffix src/foo.c test.c abc)

返回".c .c "

  1. basename
$(basename <names...>)

去除文件后缀
示例:

$(basename src/foo.c test.c abc)

返回"src/foo test abc"

2.3.2 字符串替换与分析函数

  1. subst
$(subst <src>,<dst>,<text>)

将<text>中的字符<src>替换为<dst>
示例:

$(subst aa,AA,aabbaa aAfd)

返回"AAbbAA aAfd"

  1. patsubst
$(patsubst <src_pattern>,<dst_pattern>,<text>)

使用目标字符格式替换源字符格式,常常搭配%使用,如果<src_pattern>和<dst_pattern>都包括%,那么此时%表示的字符内容是一样的。
示例:

$(patsubst %.cpp,%.o,a.cpp b.cpp)

返回"a.o b.o"

  1. $(C_SOURCES:.c=.o)
    将C_SOURCES变量中所有的.c替换成.o

  2. strip
    去掉字符串的开头和结尾的空格
    示例:

$(strip,  a.cpp b.cpp)
  1. findstring
    在某个字符串中查找指定字符串
    示例:
$(findstring a,a b c)
  1. filter
    保留指定格式的字符串
sources := a.c b.c c.c d.h
result := $(filter %.c %.s,$(sources))

返回"a.c b.c c.c"

  1. filter-out
    去除指定格式的字符串

  2. addprefix
    为字符串添加字符串

OBJ_FILES = main.o a.o b.o
PREFIXED_OBJ_FILES = $(addprefix obj/,$(OBJ_FILES))

返回"obj/main.o obj/a.o obj/b.o"

2.3.3 控制函数

  1. info
    向标准输出打印提示信息
$(info some debug info)

终端输出"some debug info"

  1. warning
    向标准输出打印,用于输出警告信息,make继续执行

  2. error
    向标准错误输出打印文本,make停止执行

2.3.4 其他函数

  1. foreach
$(foreach <var>,<list>,<text>)

将<list>中的参数逐一取出放到<var>中,然后执行<text>中的表达式

  • 循环执行中:每执行一次循环都会返回一个字符串,foreach循环会将返回的字符串汇总,不同字符串通过空格分隔
  • 循环执行结束:当整个循环结束的时候,返回汇总的字符串

示例:

name := a b c d
files := $(foreach n,$(name),$(n).o)

返回"a.o b.o c.o d.o"

  1. call
$(call <expression>,<parm1>,<parm2>,...)

调用自定义的函数或者表达式,也可以传参调用

  1. shell
    执行操作系统的shell命令,返回的是命令行命令执行的结果
    示例:
$(shell ps ajx | grep text)
  1. eval
$(eval <text>)

可以将<text>中的内容作为makefile的一部分,然后按照makefile的语法解析这些内容,无返回值

2.4 伪目标

伪目标的格式:

.PHONY:目标
目标:依赖
<tab>命令

伪目标与常规目标的区别(无.PHONY声明):

  • 常规目标会检查目标文件的修改时间与依赖文件的修改时间,如果目标文件的修改时间晚于依赖文件,则不用执行命令;反之再执行命令。
  • 伪目标无论何时都会执行命令

伪目标用来定义ALL的作用:

  • 避免与目标文件同名导致构建失败或者不小心touch了目标文件使得本应该重新编译链接的没有反应,提升鲁棒性
  • 大多数项目将ALL声明为伪目标,遵循社区约定

还用来定义无依赖对象的伪目标,例如:

.PHONY:clean
clean:rm *.o *.out

调用时要在命令行输入:“make clean”

3.编写方式

假定有如下a.c b.c c.c main.c 四个文件,将这四个文件编译链接形成一个目标文件output

3.1 Makefile+直接编译链接

output:a.c b.c c.c main.cgcc a.c b.c c.c main.c -o output

3.2 Makefile+编译+链接

output:a.o b.o c.o main.ogcc a.o b.o c.o main.o -o outputa.o:a.cgcc -c a.c a.o
b.o:b.cgcc -c b.c b.o
c.o:c.cgcc -c c.c c.o
main.o:main.cgcc -c main.c main.o

3.3 Makefile+变量

SRC = a.o b.o c.o main.o
TARGET = output
$(TARGET):$(SRC)$(CC) $^ -o $@a.o:a.c$(CC) $^ -o $@
b.o:b.c$(CC) $^ -o $@
c.o:c.c$(CC) $^ -o $@
main.o:main.c$(CC) $^ -o $@

3.4 Makefile+模式匹配

SRC = a.o b.o c.o main.o
TARGET = output
$(TARGET):$(SRC)$(CC) $^ -o $@%.o:%.c$(CC) $< -o $@

3.5 Makefile+函数

a.h和a.cpp和main.cpp文件生成一个项目的makefile文件如下:

CXX = g++
CXXFLAGS = -Wall -std=c++17SRCS = a.cpp main.cpp
OBJS = $(SRCS:.cpp=.o)
TARGET = outputall = $(TARGET)$(TARGET): $(OBJS)$(CXX) $(CXXFLAGS) -o $(TARGET) $(OBJS)%.o:%.cpp$(CXX) $(CXXFLAGS) -c $< -o $@clean:rm -f $(OBJS) $(TARGET).PHONY: all clean

问题:这里的.c文件的依赖文件.h为什么不写:
这里这么写是没有问题的,它会自动检测.c的.h依赖文件。但是会出现一个问题,如果是这里修改了.h文件,make是检测不出来依赖文件改变的,它只会看.c没变,然后就不会重新编译。因此每次修改之后都需要make clean && make重新生成。

所以可以改进一下,来可以显示生成依赖关系文件,然后-include到makefile文件中如下,这时make时候就会检测到.c对.h的依赖关系,会进行时间检测是否重新编译:

CXX = g++
CXXFLAGS = -Wall -std=c++17 -MMD -MP  # 启用依赖生成
SRCS = main.cpp utils.cpp
OBJS = $(SRCS:.cpp=.o)
DEPFILES = $(SRCS:.cpp=.d)
TARGET = appall: $(TARGET)$(TARGET): $(OBJS)$(CXX) $(CXXFLAGS) -o $@ $(OBJS)%.o: %.cpp$(CXX) $(CXXFLAGS) -c $< -o $@  #因为有MMD和MP参数所以会在执行这个的时候同时生成对应.d文件-include $(DEPFILES)  # 包含依赖关系clean:rm -f $(OBJS) $(TARGET) $(DEPFILES).PHONY: all clean

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com