VsCode多个(C/C++)源文件的编译运行(Linux)之Makefile 通用模板(极其易懂)

        在 Linux 下的一个 C/C++ 工程中源文件(.c/.cpp)较多时,如果在终端直接输入语句进行编译运行不免有些麻烦,特别是当 .c/.cpp 较多时,下面举个例子说明;

eg:如下图所示是我在 Linux 下建立的一个 C++ 工程;

VsCode多个(C/C++)源文件的编译运行(Linux)之Makefile 通用模板(极其易懂)_第1张图片

         如果直接在终端输入如下语句即能对该工程进行编译和运行,但是就语句老看不免有些冗长,如果 .cpp 文件多大几十个时则会更加麻烦;

#工程中没有使用线程
g++ main.cpp BPlusTree.cpp CLThread.cpp table.cpp -o main

#工程中使用了线程
g++ main.cpp BPlusTree.cpp CLThread.cpp table.cpp -o main -lpthread

         另一种方法便是使用 vscode 在该工程中新建一个 makefile 文件(或在终端直接进建立),如上图所示,然后 makefile 的编辑内容如下:

src=$(wildcard ./*.cpp)                #获取当前目录下的所有 .cpp 文件,可以有多个格式文件;
objs=$(patsubst %.cpp, %.o, $(src))    #把 .cpp 文件替换为 .o 文件
target=main
$(target):$(objs)
	$(CXX) $(objs) -o $(target) -lpthread 
    
%.o:%.cpp
	$(CXX) -c $< -o $@
	
#伪目标(即不会生成文件),编译完成后删除 .o 文件
.PHONY:clean
clean:
	rm $(objs) -f

        上述给出的 makefile 文件内容是对于 Linux 下的所有 C++ 工程都通用的一个模版 ,新建 makefile 并编辑保存后,在终端直接输入 make 语句就会进行编译;

VsCode多个(C/C++)源文件的编译运行(Linux)之Makefile 通用模板(极其易懂)_第2张图片

         如上图所示,可执行文件便生成了,最后在直接输入:./main 即可直接运行;

         注:如果在执行 make 命令时,make 没有安装,则按终端上的提示,对 make 进行安装即可,makefile 文件详细说明见下文;

1、Makefile 介绍

        一个 c++ 工程中的源文件不计其数,其按类型、功能、模块分别放在若干个目录中,Makefile 文件定义了一系列的规则来指定哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作,因为 Makefile 文件就像一个 Shell 脚本一样,也可以执行操作系统的命令;

        Makefile 带来的好处就是“自动化编译”,一旦写好,只需要一个 make 命令,整个工程就会完全自动编译,极大提高了软件开发的效率。make 是一个命令工具,是一个解释 Makefile 文件中置零的命令工具,一般来说,大多数的 IDE 都有这个命令,比如 Delphi 的 make,Visual C++ 的 make,Linux 下 GNU 的 make;

注:

        (1)文件命名只能是 Makefile 或 makefile ;

        (2)makefile 规则

                 一个 makefile 文件可以有一个或多个规则;

                 目标...:依赖...

                          命令(Shell命令)

                           ...

                 目标:指的是生成的目标文件名称,可以意取;

                 依赖:生成目标所需要的文件;

                 命令:通过执行命令对依赖项操作生成目标(命令前必须加 Tab );

                 makefile 中的其他规则一般都是为第一条规则服务的;

                        

2、Makefile 文件的几种常用形式

        如下图所示,是我在 Linux 下建立的一个 C++ 工程,在 Linux 下运行时需要输入以下指令:

#工程中没有使用线程
g++ main.cpp BPlusTree.cpp CLThread.cpp table.cpp -o main

#工程中使用了线程
g++ main.cpp BPlusTree.cpp CLThread.cpp table.cpp -o main -lpthread
VsCode多个(C/C++)源文件的编译运行(Linux)之Makefile 通用模板(极其易懂)_第3张图片

        如果在该目录下新建一个 Makefile 文件,则在 Linux 终端输入 make 即可运行Makefile 文件内容的形式有以下几种:

(1)makefile

app:main.cpp BPlusTree.cpp mulThread.cpp table.cpp
	g++ main.cpp BPlusTree.cpp mulThread.cpp table.cpp -o app

 注:app是生成的目标文件名,可以随意取;

(2)makefile

app:main.o BPlusTree.o mulThread.o table.o
	g++ main.o BPlusTree.o mulThread.o table.o -o app

main.o:main.cpp
	g++ -c main.cpp -o main.o

BPlusTree.o:BPlusTree.cpp
	g++ -c BPlusTree.cpp -o BPlusTree.o

mulThread.o:mulThread.cpp
	g++ -c mulThread.cpp -o mulThread.o

table.o:table.cpp
	g++ -c table.cpp -o table.o

(3)makefile

#定义变量
src=main.o BPlusTree.o mulThread.o table.o
target=app
$(target):$(src)
	$(CXX) $(src) -o $(target)

main.o:main.cpp
	g++ -c main.cpp -o main.o

BPlusTree.o:BPlusTree.cpp
	g++ -c BPlusTree.cpp -o BPlusTree.o

mulThread.o:mulThread.cpp
	g++ -c mulThread.cpp -o mulThread.o

table.o:table.cpp
	g++ -c table.cpp -o table.o

(4)makefile

#定义变量
src=main.o BPlusTree.o mulThread.o table.o
target=app
$(target):$(src)
	$(CXX) $(src) -o $(target)

%.o:%.cpp
	$(CXX) -c $< -o $@

(5)makefile

src=$(wildcard ./*.cpp)                #获取当前目录下的所有 .cpp 文件,可以有多个格式文件;
objs=$(patsubst %.cpp, %.o, $(src))    #把 .cpp 文件替换为 .o 文件
target=main
$(target):$(objs)
	$(CXX) $(objs) -o $(target) -lpthread 
    
%.o:%.cpp
	$(CXX) -c $< -o $@
	
#伪目标(即不会生成文件),编译完成后删除 .o 文件
.PHONY:clean
clean:
	rm $(objs) -f

注:第(5)个 makefile 文件一般通用所有的,无需修改内容; 

       上述变量、函数、符号说明,见下文;

        需要特别说明的是,命令前使用的是 Tab ,但是 vscode 一般默认 Tab 为四空格,此时需要对其进行修改,否则会报错:

vscode 默认四空格修改为 Tab 方法:vscode 编辑 makefile 文件,执行make操作时显示“Makefile:5: *** 遗漏分隔符 。 停止。“(终极解决办法)_小朋友-CSDN博客

3、Makefile 的基本原理

(1)命令在执行之前,需要先检查规则中的依赖项是否存在;

        a.如果存在,执行命令;

        b.如果不存在,向下检查它的规则,检查有没有一个规则是用来生成这个依赖的,如果找到了,则执行该规则中的命令;

(2)检测更新,在执行规则中的命令时,会比较目标和依赖文件的时间;

        a.如果依赖的时间比目标时间晚,需要重新生成目标;

        b.如果依赖的时间比目标时间早,目标不需要更新,对应规则中的命令不需要被执行;

4、Makefile 的变量

(1)自定义变量

        变量名=变量值

var=hello

#获取变量的值 $(变量名)
$(var)

(2)预定义变量

        AR:归档维护程序的名称,默认值为 ar;

        CC:C 编译器的名称,默认值 gcc;

        CXX:C++ 编译器的名称,默认值 g++;

        $@:目标的完整名称;

        s<:第一个依赖文件的名称;

        s^:所有依赖文件的名称;

        注:后三个只能用在命令中;

app:main.cpp a.cpp b.cpp
    g++ -c main.cpp a.cpp b.cpp -o app

#自动变量只能在规则的命令中使用
app:main.cpp a.cpp b.cpp
    $(CC) -c $^ -o $@

5、Makefile 的模式匹配

main.o:main.cpp
    g++ -c main.cpp

BPlusTree.o:BPlusTree.cpp
    g++ -c BPlusTree.cpp

CLThread.o:CLThread.cpp
    g++ -c CLThread.cpp

table.o:table.cpp
    g++ -c table.cpp
%.o:%.cpp

# %:通配符,匹配一个字符串;两个 % 匹配的是同一个字符串;

6、Makefile 的函数

(1)$(wildcard PATTERN...)

        功能:获取指定目录下指定类型的文件列表;

        参数:PATTERN指的是某个或多个目录下的对应的某种类型的文件,如果有多个目录,一般使用空格间隔;

        返回:得到的若干个文件列表,文件名之间使用空格间隔;

        示例:

                $(wildcard ./*.cpp)

                返回值格式:main.cpp BPlusTree.cpp CLThread.cpp table.cpp

(2)$(patsubst , , )

        功能:查找 中的单词(单词以“空格”、“Tab”或“回车“”换行”分隔)是否符合模式 ,如果匹配的话,则以 替换;

        可以包括通配符 % ,表示任意长度的字符串。如果  中也包含 % ,那么 中的这个 % 将是 中的那个 % 所代表的字串。(可以用 \ 来转义,以 \% 来表示真实含义的 % 字符)

        返回:函数返回被替换过后的字符串;

        示例:

                $(patsubst %.cpp, %.o, $(src))

                返回值格式:main.o BPlusTree.o CLThread.o table.o

                

你可能感兴趣的:(Linux,操作系统,vscode,linux,ide)