gcc main.c -c #######生成main.o
gcc main.c -c
和 gcc -c main.c
这两个命令在功能上是完全相同的,它们都会告诉 GCC 编译器只编译 main.c
文件而不进行链接操作,生成一个名为 main.o
的目标文件(object file)。
这里的 -c
选项是 GCC 编译器的一个参数,用于指示编译器只进行编译操作,不执行后续的链接步骤。在这个选项中,-c
总是作为一个独立的参数出现,不论它前面是否有其他参数(如源文件名)。
因此,无论你将 -c
放在源文件名之前还是之后,只要它出现在命令行中,GCC 都会识别并应用这个选项。所以,gcc main.c -c
和 gcc -c main.c
都会被 GCC 解释为“只编译 main.c
文件,不生成可执行文件”。
总结来说,这两个命令没有区别,你可以根据自己的喜好或项目规范来选择使用哪一个。不过,为了保持一致性,很多项目或教程可能会倾向于使用 gcc -c main.c
这种形式,因为它更明确地表明了 -c
选项的意图,即将接下来的文件作为源文件进行编译。但是,从 GCC 的角度来看,这两种形式都是有效的。
hello: main.c
gcc -o hello main.c
对于 GCC 来说,-o 选项和紧随其后的文件名在这个上下文中可以放在命令行的任何位置,只要 -o 选项后面紧跟着的是你想要指定的输出文件名。
ll / start main.c 查看时间
版本1
hello: main.c print.c show.c -------一般要加.h文件
gcc -o main.c print.c show.c
是不是可以理解用=赋值时不需要加$ 而其他地方调用这个变量时加$
在 Makefile 中,使用 =(或其他赋值操作符,如 :=、?=、+=)为变量赋值时,不需要在变量名前加 $。这些赋值操作符是用来定义或修改 Makefile 中的变量的。
然而,在 Makefile 的其他地方(如目标(target)的定义、命令(command)中),当您想要引用之前定义的变量的值时,就需要在变量名前加上 $ 符号,并可能还需要使用括号 () 来避免解析上的歧义,特别是在变量名与后面的文本紧密连接时。但是,在大多数情况下,如果变量名后面紧跟着的是空格、制表符、冒号(:)、等号(=)或其他非字母数字字符,那么括号就不是必需的。
TARGET = hello
all: $(TARGET)
$(TARGET): main.o print.o
gcc -o $(TARGET) main.o print.o
版本2
相较于版本1 make只会编译修改后的文件 比如修改main.c之后gcc -c main.c之后直接gcc -o 生成可执行文件
CXX = g++
TARGET = hello
OBJ = main.o print.o show.o
$(TARGET): $(OBJ)
$(CXX) -o $(TARGET) $(OBJ)
main.o: main.c
$(CXX) -c main.c
print.o: print.c
$(CXX) -c print.c
show.o: show.c
$(CXX) -c show.c
版本3
$^ 表示所有的依赖文件 ....一般把所有.o连接成可执行文件
$@ 表示生成的目标文件
$< 代表第一个依赖文件。。。每个.o与.c 一一对应
-o
选项的作用是告诉编译器将输出写入到指定的文件中,
-c 具体来说,当你在编译 .c
、.cpp
或其他源代码文件时,加上 -c
选项后,编译器会将源代码编译成目标代码(object code),通常这些目标代码会被保存在以 .o
(对于 UNIX-like 系统)或 .obj
(对于 Windows 系统)为扩展名的文件中,而不是生成可执行文件(executable file)。
CXX = g++ # 设置 C++ 编译器为 g++
TARGET=hello # 设置最终生成的可执行文件名为 hello
OBJ=main.o print.o show.o # 设置编译过程中生成的目标文件(.o 文件)列表
CXXFLAGS =-c -Wall # 设置 C++ 编译器的标志,这里 -c 表示只编译不链接,-Wall 表示开启所有警告
# 注意:这里有一个错误,$(OBJ) 前的空格应该去掉,否则 Makefile 会报错
$(TARGET): $(OBJ) # 定义生成 TARGET(即 hello)的规则,它依赖于 OBJ 列表中的文件
$(CXX) -o $@ $^ # 使用 CXX 编译器,将 $^(所有依赖文件的列表)链接成 $@(目标文件名,即 hello)
%.o: %.cpp # 定义了一个模式规则,用于从 .cpp 文件编译出 .o 文件
$(CXX) $(CXXFLAGS) $< -o $@ # 使用 CXX 编译器和 CXXFLAGS 编译 $<(第一个依赖文件名,即 .cpp 文件)并输出到 $@(目标文件名,即 .o 文件)
# 注意:这里的 CXXFLAGS 包含了 -c,但在链接阶段我们不需要它。通常,我们会为编译和链接分别设置不同的变量
.PHONY: clean # 声明 clean 是一个伪目标,它不会对应到文件名 防止该路径下有clean文件
clean: # 定义 clean 目标的规则
rm -rf *.o $(TARGET) # 删除所有 .o 文件和 TARGET 文件,清理构建结果
-Wall
是 GCC(包括 G++,因为 G++ 是 GCC 的 C++ 前端)编译器的一个命令行选项,用于在编译过程中开启尽可能多的警告信息。这里的 "all" 并不是指字面上的“所有”警告,因为 GCC 开发者可能会认为某些警告对于大多数用户来说不是很有用,或者可能会引入噪音,因此默认情况下可能不会开启它们。但是,-Wall
选项会开启那些被认为是普遍有用和重要的警告
$(CXX) $(CXXFLAGS) $< -o $@
这个命令本身是将 .cpp
(或任何其他通过 %.o: %.xxx
规则指定的源文件类型)编译成 .o
文件。如果你想要编译 .c
文件,你应该使用 C 编译器(如 gcc
)而不是 C++ 编译器(如 g++
),并且可能需要调整你的 Makefile 规则来匹配 .c
文件而不是 .cpp
文件。
%.o: %.cpp
$(CXX) -c $< -o $@
这个规则定义了一个模式规则(pattern rule),它告诉 make 如何从任何 .cpp
文件生成对应的 .o
文件。每当 make 需要构建一个 .o
文件,并且存在一个与之对应的 .cpp
文件时,它就会自动应用这个规则。
定义了一个模式规则(pattern rule),它会自动将当前目录下所有.cpp
文件编译成对应的.o
文件。这里的%
是一个通配符,代表任意长度的字符串。因此,对于任何.cpp
文件,比如main.cpp
,Makefile都会应用这条规则来生成main.o
。
$<
代表规则中的第一个依赖项,即.cpp
文件。$@
代表规则中的目标项,即.o
文件。$(CXX)
是一个Makefile变量,通常用来指定C++编译器的路径和名称。如果你没有显式地设置它,它通常会默认为g++
(在大多数Linux发行版和Unix系统中)。
所以,当你运行make
命令时,Makefile会查找所有.cpp
文件,并对每个文件应用这条规则来生成对应的.o
文件。
具体来说,%.o: %.cpp
表示“对于任何 .o
文件,如果有一个同名的 .cpp
文件(除了扩展名不同),就使用这条规则来构建它”。$<
代表规则中的第一个依赖项(在这里是 .cpp
文件),而 $@
代表规则中的目标文件(在这里是 .o
文件)。
因此,当你运行 make 并且指定了一个目标(比如一个可执行文件),而该目标依赖于多个 .o
文件时,make 会自动查找这些 .o
文件的依赖项(即 .cpp
文件),并使用上述规则将它们编译成 .o
文件。这个过程会对所有需要的 .cpp
文件进行,从而将所有相关的 .cpp
文件编译成 .o
文件。
请注意,这个过程是递归的,因为 .o
文件本身可能还依赖于其他文件(如头文件),但一旦 .cpp
文件被编译成 .o
文件,这个特定的规则就完成了它的工作。其他依赖项(如头文件)的更新可能会影响是否需要重新编译 .cpp
文件,但这由 make 的依赖关系追踪机制来处理。
版本4
# 设置CXX变量为g++,即C++编译器
CXX=g++
# 设置TARGET变量为hello,这是最终生成的可执行文件的名称
TARGET=hello
# 使用wildcard函数找到当前目录下所有的.cpp文件,并将它们赋值给SRC变量
SRC=$(wildcard *.cpp)
# 使用patsubst函数将SRC变量中的.cpp扩展名替换为.o,得到OBJ变量,即所有目标文件(.o文件)的列表
OBJ=$(patsubst %.cpp, %.o, $(SRC))
# 设置CXXFLAGS变量,包含编译选项-c(只编译不链接)和-Wall(显示所有警告)
# 注意:在构建最终目标(可执行文件)时,通常不需要-c选项
CXXFLAGS=-c -Wall
# 定义最终目标(hello可执行文件)的依赖关系,它依赖于OBJ变量中列出的所有.o文件
$(TARGET): $(OBJ)
# 使用CXX(g++)编译器和OBJ变量中列出的所有.o文件来链接生成最终目标(hello)
# $@代表当前规则中的目标文件名(hello),$^代表所有依赖项(.o文件)
$(CXX) -o $@ $^
# 定义一个模式规则,用于从.cpp文件编译出.o文件
# $<代表规则中的第一个依赖项(.cpp文件),$@代表目标文件名(.o文件)
%.o: %.cpp
$(CXX) $(CXXFLAGS) $< -o $@
# 声明clean是一个伪目标,它不会对应到文件名
# 这防止了如果当前目录下有一个名为clean的文件时,make clean命令不会执行清理操作
.PHONY: clean
# 定义clean目标的规则
# 使用rm命令删除当前目录下所有的.o文件和TARGET变量指定的可执行文件(hello),以清理构建结果
clean:
rm -rf *.o $(TARGET)
wildcard函数是Makefile中用于查找文件的函数,它可以在Makefile中使用通配符来查找指定目录下的文件,并将结果返回给Makefile。这个函数在Makefile中非常有用,因为它可以帮助自动化构建过程中的文件查找和处理。
假设有一个名为src
的子目录,想要查找该目录下所有以.c
结尾的文件,可以这样做:
SRC = $(wildcard src/*.c)
patsubst函数(pattern substitute)是GNU Make中的一个功能强大的函数,其主要作用是在Makefile中进行模式替换。具体来说,它可以将一个字符串中符合特定模式的子串替换为另一个字符串。这个函数在自动化构建过程中非常有用,特别是在处理文件名、路径或进行其他类似的字符串转换操作时。
$(patsubst <pattern>,<replacement>,<text>)
<pattern>
:需要匹配的模式,可以包含通配符%
,表示任意长度的字串。<replacement>
:用于替换匹配到的模式的字符串。如果<replacement>
中也包含%
,那么它将被<pattern>
中的%
所匹配到的字串替换。<text>
:需要进行替换的字符串列表,可以是单个字符串或包含多个字符串的变量