如何创建 G++ Makefile 文件

Blog
Author:
Amir KirshAmir Kirsh
Published On:
2月 7, 2023
Estimated reading time:
1 minute

目录

对于各行业、各学科来说,C++ 仍然是最受欢迎的一种编程语言。这是有充分理由的。这意味着,目前存在多种可用的 C++ 工具,它们各有优缺点。其中,GNU 编译器套件 (GCC) 具有广泛的特性和能力,因此是最受欢迎的工具之一。随着这种的工具的普及,GCC 及其 C++ 专用工具,特别是标准 G++ makefile 文件,都值得深入研究。

什么是 GCC?

GCC 是 GNU Compiler Collection(GNU 编译器套件)的英文缩写。它包括适合多种软件语言的前端(在编译器领域中,前端指的是将软件语言转换成通用中间表示的组件。根据中间表示,编译器后端可以创建适合目标架构和操作系统的适当运行时工件)。GCC 最初是作为 GNU 操作系统的编译器编写而成的。

GCC 包括适用于以下方面的前端:

GCC 还适用于:Objective-CFortranAdaGoD 以及这些语言的库。

GNU 系统尊重用户自由,属于 100% 免费软件。

C++ 开发工作效率挑战 –

如何优化 C++ 开发?只有充分理解我们在工作效率方面所面临的挑战,并找到尽可能减少困难的方法,才能实现优化。欲了解更多信息,请观看我们最新的网络研讨会视频!

立即观看

什么是 gcc(小写)?

gcc 命令调用 GNU 编译器套件的编译器驱动程序。你会不会觉得 gcc 写错了?不,不是的。我们故意使用的小写。为什么呢?GCC 是应用程序的官方名称,而 gcc 则是关于如何在代码编写过程中调用 GNU 编译器套件。

在文件上运行 gcc 命令时,通过文件扩展名,可以判断该文件是否需要处理。默认 gcc 会判断为 C++ 源代码的文件扩展名有“.cpp”和“.cc”。gcc 还会假定“.c”文件采用 C 语言编写而成。

例如,运行 gcc -o [output_file] [input_file.c] 时,判断输入文件为 C 代码,然后用 C 编译器 (cc1) 处理编译过程。如果输入文件的扩展名为 .cpp 或 .c++,那么判断文件为 C++ 代码,然后用 C++ 编译器 (cc1plus) 处理编译过程。

为什么使用 G++?

在大部分情况下,只要编译 C++ 代码,可能就需要 C++ 编译器。你可以直接使用 g++ 进行操作。

运行 G++ 时,它会把源代码视为 C++,因此,从这方面来看,‘G++’就是‘gcc -x c++’。gcc 确实可以检测你目前是否正在编译 C++ 文件,然后按此进行编译;但是,同样地,如果你已然知晓自己正在编译 C++ 项目,那么明确要求使用 C++ 编译器也很合理。

一旦 G++ 驱动程序链接 C++ 程序,通常它会自动链接 libstdc++ 库,GCC 附带的标准 C++ 库(切记大写 GCC 与小写 gcc 程序之间的区别)。因此,从这方面来看,‘g++’ 和 ‘gcc -lstdc++’ 是相同的(还有更多信息)。

G++ 与 gcc 不同。由于 C++ 程序通常采用异常项,创建共享库或主执行文件时,G++ 可以自动添加 -shared-libgcc,这种做法是正确的(点击此处了解更多详细信息)。因此,从这方面来看,‘g++’ 等同于 ‘gcc -shared-libgcc’。

如何在 Linux/Mac/Windows 等操作系统上安装 GCC

通常 GCC 已经纳入了 Linux 发行版;不过对于其他操作系统,或者当你想安装不同的版本时,可以直接从 GNU 网站上下载

使用 Windows 版 GCC,环境必须兼容 Linux。使用 MinGWCygwinWSL 即可实现。

什么是 Makefile 文件?什么是 G++ Makefile 文件?

makefile 是一种包含 make 程序指令的文件。make 程序可以实现自动化的源代码文件构建过程。make 工具历史较长(首版于 1976 年发布),目前仍然使用广泛。它可以直接使用,也可以结合 CMake 等其它工具一起使用(如欲了解更多有关 CMake 的信息,你可以阅读我们的文章《利用 CMake 进行交叉编译》CMake 生成器》CMake Make《探索有关 CMake 的讨论》《现代 CMake 窍门和技巧》。如欲了解(不依赖 make 的)构建工具 ninja,请阅读我们的文章CMake Ninja 组合》

g++ makefile 文件是一种专门的 makefile 文件,其中包含了采用 g++ 编译器编译和链接 C++ 源代码的指令。这种 makefile 文件通常包括源文件与目标可执行文件之间的依赖关系,以及需要传入 g++ 的任何编译器标记或选项。make 程序读取 makefile 文件,解释其指令,然后根据 makefile 文件中指定的依赖关系和指令,构建目标可执行文件。

如欲了解更多信息,你可以阅读我们的文章《什么是 GNU make?如何安装 GNU make?》

用 Incredibuild 加速 C++ 构建

在需要时,利用 Incredibuild 的进程虚拟化技术和构建缓存,可以大幅度缩短编译时间,并获得所需的能力。现在就免费试试吧!

如何创建 G++ Makefile 文件

主要语法规则非常简单:

targets : prerequisites

        recipe

现在我们来展开讲讲规则。

目标是文件时,比如说,对象文件或可执行文件,如果其依赖文件存在任何变更,那么目标文件需要重新编译或重新链接。

配方文件告诉程序如何更新目标文件。此外,如果任何依赖文件本身就是目标文件,那么首先更新这些文件。

下例所示 Makefile 文件来自可靠权威来源。我们给出了一些评论。

由于所有 C 文件均包含 defs.h,如果涉及 defs.h,那么我们还需要:

  1. 重新编译全部八份对象文件
  2. 编译并链接,以生成可执行文件

但是,如果只涉及 command.h,那么我们可以:

  1. 只需重新编译 command.o 和 files.o
  2. 编译并链接,以生成可执行文件

但是,如果涉及单个.c 文件,例如 utils.c,那么:

  1. 仅需重新编译 utils.o
  2. 编译并链接,以生成可执行文件

需要记住的一个关键要点是:建立良好的依赖层次结构和 Makefile 文件可以节省编译时间。

使用宏

在 Makefile 文件中,宏可以用来定义变量。这些变量要么可以存储文本字符串,要么可以建立文本字符串列表。然后,在整个 Makefile 文件中,都可以使用这些变量,简化并减少构建程序所用命令中的重复利用现象。宏可以利用 = 运算符进行定义,然后用 $ 运算符引用。例如,我们可以定义一个名为“CXX”的宏,存储前往 C++ 编译器的路径,然后在整个 Makefile 文件中,例如在 $(CXX) -o program program.cpp 文件的各种命令中使用该宏。

以下所示为采用了宏的 makefile 文件:

# Makefile for C++ program 

# Compiler and flags 

CXX = g++
CXXFLAGS = -std=c++11 -Wall -O2 
# Target and dependencies 
TARGET = myprogram 
OBJS = main.o foo.o bar.o 
# Build and run 
all: $(TARGET)
    ./$(TARGET)

$(TARGET): $(OBJS)
    $(CXX) $(CXXFLAGS) -o $@ $^

%.o: %.cpp
    $(CXX) $(CXXFLAGS) -c -o $@ $< 
# Cleanup 
clean:
    rm -f $(TARGET) $(OBJS)

此 Makefile 文件采用 g++ 作为编译器 (CXX = g++),还设置了编译器标记 (CXXFLAGS = -std=c++20 -Wall -O2)。TARGET 变量设置为最终可执行文件的名称,OBJS 变量为构建程序所需的对象文件列表。

不设置参数运行 make 时,默认目标文件为所有目标文件。它取决于 TARGET,在构建后运行程序。

$(TARGET) 目标文件取决于 $(OBJS),然后二者链接在一起,以创建最终可执行文件。%.o:%.cpp 规则是一种基于 C++ 源文件构建对象文件的匹配模式规则,clean 目标文件用于删除对象文件和最终可执行文件。

使用此 Makefile,需将其保存到名为“Makefile”的文件中(在某些系统上,名为“makefile”),然后在相同目录下运行 make。这样就可以构建程序,运行程序。要清除对象文件和最终可执行文件,运行 make clean。

如何运行 make

非常简单,只需输入:make 或 include 目标文件名称。就会看到 Makefile 并跟进完成操作。

g++ makefile 文件创建注意事项

使用宏控制编译器版本

在上例中,$(CXX) 扩展或替换为 g++。采用此变量,你可以控制所使用的编译器。建议使用更多定义,设置编译标记和链接标记,同时,通过设置包含目录的变量,控制源文件、对象文件和二进制文件,支持你的项目结构。

 

只编译需要编译的

Makefile 或 CMake 等构建系统可用于管理编译过程。这些系统有助于识别源文件之间的依赖关系,同时在发生变更时,只编译必要的文件。

如何加速 G++ Makefile,以节约时间和资源

方法就是:确保你已经建立了良好的依赖层级结构,且 makefile 文件能够体现出这种层次结构;确保当代码变更时,你可以尽可能减少编译工作。在这一方面,值得一提的是:C++ 模块可以引起重大变化。C++ 模块允许预编译和缓存模块接口,从而加快了编译时间。每次小变更无需重新编译和链接整个代码库,只需重新编译变更的模块及其所依赖的模块即可。这样可以大幅缩短构建时间,尤其是在包含许多依赖关系的大型代码库中。此外,C++ 模块可以在编译时解析依赖关系,对代码库中需要重构的部分进行更细化的控制,从而减少需要重新编译的代码量。

 

常见问题

1.什么是 GNU

GNU(发音为“guh-noo”)是“GNU’s Not Unix!”的递归缩写,意即“GNU 并非 Unix”。

GNU 是一种使用广泛的免费开源操作系统和软件开发环境。由 Richard Stallman 于 1983 年创建而成。当时广泛使用的 Unix 操作系统开始转为专有模式,为了打破这样的局面,Richard Stallman 发起了 GNU 项目。GNU 项目的初衷是为了创建可供所有人使用的免费开源 Unix 版本。

GNU 项目已经开发了大量软件工具和实用程序,包括 GCC(GNU 编译器套件)。该套件包括适用于 C、C++、Objective-C、Fortran、Ada 等语言的各种编译器。其中最著名的 GNU 项目就是 GNU/Linux 操作系统。它是基于 Linux 内核和 GNU UserLAnd 实用程序的类 Unix 操作系统。

GNU 的理念基于四个基本的软件自由:自由运行程序,自由研究和修改程序,自由分发副本,自由分发修改版本的副本。

更多信息,请访问:https://www.gnu.org/

 

2.不使用 make,可以编译 C++ 吗?

是的,不使用构建工具(如 make),也可以编译 C++ 代码。其中一种常见的方法就是使用命令行编译器 g++。这种编译器是 GNU 编译器套件 (GCC) 的一部分。使用 g++ 编译 C++ 程序的基本语法如下:

g++ -o [executable_name] [source_file_name].cpp

例如,若你有一份名为“main.cpp”的 C++ 源文件,要想创建一份名为“program”的可执行文件,你可以使用以下命令:

g++ -o program main.cpp

此命令将创建一个名为“program”的可执行文件。然后你就可以在系统上运行这份 program 可执行文件。注意:‘-o’ 标记可用于指定输出文件的名称。

除了 g++ 以外,你也可以使用 clang++ MSVC 等编译器,编译 C++ 代码,不必使用 make。

 

3.没有 g++,可以使用 Make 吗?

是的,没有 g++,也可以使用 Make。Make 是一种构建和编译软件程序的构建自动化工具。它适用于各种编程语言或编译器,不受任何限制。Make 使用 Makefile 文件,该文件包含一组描述如何构建软件的规则和依赖关系。Makefile 文件指定了构建程序需要执行的命令,而 Make 则负责按照正确的顺序执行命令。

因此,使用 Make 时,你可以搭配任何编译器,如 clangMSVCicc 等。在 makefile 文件中,你只需指定需要使用的编译器以及构建程序的规则即可。

例如,用 clang 构建程序,可以在 makefile 文件中指定以下内容:

CC=clang
CXX=clang++

然后,用 $(CC) 或 $(CXX) 调用 make 配方文件中的编译器。

综上所述,虽然 Make 和 g++ 经常搭配使用,但二者并不相互依赖,你可以在任何编译器中使用 Make。

在 Visual Studio 上加速 C++ 构建

现在,在 Visual Studio 中以更快的速度构建 C++ 代码吧,开箱即用!