0 推荐一个教程

1 预知识

1.1 不同操作系统对C语言的编译

1.1.1 Windows操作系统

在Windows系统中,有一个最常用的集成开发环境IDE:Visual Studio,一般而言,不是特别复杂的工程都可以在这个Visual Studio中一次性完成。

如果我们不用Visual Studio呢?那怎么开发c语言工程呢。

第一步:使用文本编辑器编写 C 语言源代码文件

  • 要做什么:新建文件,编写符合 C 语言语法的代码,保存为以 .c 为后缀名的源代码文件(例如 main.c、calc.c)。
  • 推荐工具
    • 基础款:记事本(Windows 自带)、Notepad++(轻量、支持语法高亮,比记事本更友好);
    • 进阶款:VS Code(免费、有功能强大的插件)、Sublime Text。

第二步:安装并配置 C 语言编译器(核心环节)

  • 要做什么:安装一款 C 语言编译器,配置系统环境变量(可选但强烈推荐),确保能在命令行中直接调用编译器命令。
  • 为什么要这么做
    1. 编译器是连接 C 语言源代码和机器码的核心桥梁,它的作用是将人类可读的 .c 源文件(高级语言)编译(compile) 转换为计算机可识别的二进制目标文件(通常以 .o.obj 为后缀名);
    2. 没有编译器,.c 源文件只是一堆纯文本,无法被计算机执行,这是编译型语言开发的必要环节
    3. 配置环境变量的目的是:无需在命令行中输入编译器的完整路径(如 D:\MinGW-w64\mingw64\bin\gcc.exe),只需直接输入 gcc 即可调用编译器,简化后续操作。
  • 推荐工具
    • MinGW-w64(Windows 环境首选,免费开源、轻量,兼容 GCC 编译器,支持 32/64 位系统);
    • TDM-GCC:另一个 MinGW 的打包版本,安装简单。
    • MSYS2 + GCC:更现代、更新及时的环境。
    • MSVC(微软编译器,Visual Studio 自带,若不想装完整 VS,可安装「Visual Studio Build Tools」单独获取,但是不推荐此时用 MSVC,因为它通常绑定在 Visual Studio 中,命令行使用较复杂 )。

问题1:MinGW-w64、MSVC等都是C 语言编译器吗?

✅不完全是,二者不能简单等同于 “C 语言编译器”,性质有明确区别。

  1. MSVC:包含 C/C++ 编译器,是一套完整的编译工具链(狭义上可称其编译器)

    严格来说,MSVC(Microsoft C/C++ Compiler,微软 C/C++ 编译器)的核心编译器组件是 cl.exe(对应 C 语言编译,也支持 C++),我们日常说的 “MSVC”,其实是一套完整的 Windows 平台 C/C++ 编译工具链(包含编译器、链接器、库文件、头文件、编译辅助工具等)。

    它可以直接编译 C 语言源代码,是 C 语言编译器的一种,但 “MSVC” 这个称呼的范畴大于 “单一 C 编译器”,只是在日常开发中,我们常简化将其称为 “MSVC 编译器”。

  2. MinGW-w64:不是编译器,是一套Windows 平台下的开源工具集 / 编译环境

    MinGW-w64 的核心是把 Linux 平台下的 GCC 编译工具链移植到 Windows 系统中,让开发者能在 Windows 上直接使用 GCC 相关工具,它本身不具备编译器的核心功能,只是一个 “载体” 或 “环境包”

    这套工具集中包含了 C 语言编译器(gcc.exe)、C++ 编译器(g++.exe)、链接器(ld.exe)、调试器(gdb.exe)、C/C++ 标准库、以及适配 Windows 系统的相关依赖文件,方便开发者在 Windows 上进行跨平台 C/C++ 开发。

问题 2:GCC、G++ 又是什么?

✅GCC 和 G++ 都属于GNU 工具链中的核心编译工具

  1. gcc全称:GNU Compiler Collection(GNU 编译器集合),注意 “Collection” 是 “集合” 的意思,早期 GCC 仅指 GNU C Compiler(GNU C 语言编译器),后来功能扩展,支持 C、C++、Java、Go 等多种语言,因此更名为 “编译器集合”。
  2. g++可以简单理解为gcc在c++语言上的拓展,它支持 C++ 语言的所有语法特性,默认链接 C++ 标准库(同时兼容 C 语言标准库),针对 .cpp 后缀文件进行处理;另外,g++ 也可以兼容编译 C 语言代码(会将 .c 文件当作 C++ 代码处理,语法要求更严格),但反之 gcc 无法直接编译 C++ 代码(缺少 C++ 标准库链接和语法支持)。

问题 3:MinGW-w64、MSVC 等和 GCC、G++ 有什么联系和区别?

核心目标一致:无论是 MinGW-w64、MSVC,还是 GCC、G++,最终目的都是将 C/C++ 高级语言源代码转换为对应平台可执行的二进制文件,支撑 C/C++ 项目的编译构建,是编译型语言开发的核心工具。

MinGW-w64 与 GCC、G++ 是 “载体与核心” 的关系:GCC、G++ 的原生运行平台是 Linux/Unix,而 MinGW-w64 的核心价值就是将 GCC、G++ 等 GNU 工具链移植并打包,使其能在 Windows 系统上正常运行—— 也就是说,你在 Windows 上通过 MinGW-w64 调用的 gcc.exeg++.exe,本质上就是移植后的 GNU C/C++ 编译器,MinGW-w64 为其提供了 Windows 平台的运行环境、系统适配库、辅助工具等支撑。

【注意,并不是说gcc、g++不能在Windows上运行,而是“可以直接运行”但并不能“能生成可用的 Windows 程序”,它还是按 Linux 的方式生成 ELF 文件、链接 glibc,那这个程序Windows 根本无法执行! “MinGW-w64 不单单只是个打包的作用”,它是 GCC 的 Windows 后端实现,重写了运行时和链接逻辑

MSVC 是微软专属的 Windows C/C++ 完整工具链,暂时可以理解为微软家不用gcc,自己自研了另一套编译工具。

第三步:手动编译源代码(预处理 → 编译 → 汇编 → 链接)

  • 要做什么:打开命令行工具(CMD 或 PowerShell),切换到 .c 源文件所在目录,执行编译器命令,完成编译操作。

  • 具体操作

    1. 预处理(Preprocessing)

      1
      gcc -E main.c -o main.i
      • 生成 main.i:展开所有 #include#define、处理条件编译等。
      • 🔍 为什么:C 语言的宏、头文件等是“文本替换”机制,必须在真正编译前处理完毕。
    2. 编译(Compilation to Assembly)

      1
      gcc -S main.i -o main.s
      • 生成 main.s:将 C 代码转为汇编语言(与 CPU 架构相关)。
      • 🔍 为什么:编译器前端将高级语言逻辑转化为低级但人类仍可读的汇编指令。
    3. 汇编(Assembly to Object Code)

      1
      gcc -c main.s -o main.o
      • 生成 main.o(或 .obj):将汇编代码转为二进制目标文件(机器码,但尚未可执行)。
      • 🔍 为什么:汇编器把助记符(如 mov, call)翻译成 CPU 能直接执行的二进制操作码。
    4. 链接(Linking)

      1
      gcc main.o -o main.exe
      • 生成 main.exe:将目标文件与标准库(如 printf 所在的 libc)合并,生成完整可执行文件。
      • 🔍 为什么:你的程序调用了库函数(如 printf),这些函数的实现不在你的 .c 文件中,链接器负责“拼接”所有模块,并解析函数地址。

1.1.2 Linux操作系统

在Linux操作系统下,集成开发环境不常见,也没有太多使用的。因为在Liunx环境下,大多数是基于命令行界面进行开发,那它里面就把源代码编辑、工程管理等拆分为了很多步骤。简单说就是把Windows中Visual Studio一次性完成的功能分开步骤来做了。

首先,Liunx下著名的代码编辑器——Vi、Vim

其次,Liunx下预处理、编译、汇编、链接——gcc/g++

当程序很简单,只有几个儿源文件时,直接就可以用gcc命令编译它。可是,如果我们的程序包含几十上百个源文件时该咋整?用gcc命令逐个去编译时,就发现很容易混乱而且工作量大,所以出现了make工具

1.2 Make工具

1.2.1 Make简介

make工具可以看成是一个智能的批处理工具。它本身并没有编译和链接的功能,而是用类似于批处理的方式一通过调用makefile文件中用户指定的命令来进行编译和链接的。

1.2.2 makefile文件

简单的说就像一首歌的乐谱,make工具就像指挥家,指挥家根据乐谱指挥整个乐团怎么样演奏,make工具就根据makefile中的命令进行编译、汇编和链接的。

所以,makefile文件中肯定就包含了调用gcc(也可以是别的编译器)去编译某个源文件的命令。

makefile在一些简单的工程完全可以人工拿下。但同样的问题,当工程非常大的时候,手写makefile也是非常麻烦的,如果换了个平台makefile又要重新修改,这时候就出现了下面的CMake工具

1.2.3 CMake工具

CMake可以更加简单的生成makefile文件给上面那个make用。当然CMake还有其他更牛X功能——就是可以跨平台生成对应平台能用的makefile,我们就不用再自己去修改了。

  • 在Windows操作系统中,若安装了Visual Studio,就可以使用CMake生成Visual Studio的工程文件;
  • 在Liunx操作系统中,CMake用于生成Make的输入文件——makefile;

可是CMake根据什么生成makefile文件呢?

它又要根据一个叫CMakeLists.txt文件(学名组态档)去生成makefile。

从上面捋下来,看起来整个过程就像是套娃——只要哪个过程人工处理变复杂了,就开发一个工具简化人的工作。到这里暂时中介套娃了,程序员就必须自己手写CMakeLists.txt文件了

2 快速上手教程

2.1 初步体验

十分注意,下面的演示错了,就因为一个中文路径,导致我浪费了一上午查找原因。所以,要使用CMake,必须把工程建在全英文目录下面。

本节通过一个小项目,先来看一下Cmake最简单的用法。

首先,创建一个项目文件夹:hellowaorld,并用VSCode打开这个文件夹

然后,创建几个文件:

1
2
3
4
5
6
7
8
9
10
11
// helloworld.c文件
#include <stdio.h>
#include "myhead.h"

int main()
{
show_hello();
show_world();
printf("OK\r\n");
return 0;
}
1
2
3
4
5
6
7
8
// myhead.h文件
#ifndef __MYHEAD_H__
#define __MYHEAD_H__

void show_hello();
void show_world();

#endif
1
2
3
4
5
6
// hello.c文件
#include <stdio.h>
void show_hello()
{
printf("hello ");
}
1
2
3
4
5
6
// world.c文件
#include <stdio.h>
void show_world()
{
printf("world\r\n");
}

上述文件的目录结构如下:

1
2
3
4
5
- helloworld
├── helloworld.c
├── myhead.h
├── hello.c
├── world.c

接下来,再在hellowaorld文件夹下创建一个文件CMakeLists.txt,这是CMake的项目配置文件,文件名称必须是这个,不能随意。此外,虽然这个文件的后缀是.txt,但它不是简单的文本文档,在CMake中是一个脚本文件,CMake会解析其中的指令,并根据指令生成相应的构建文件。

1
2
3
4
5
6
7
8
# 指定CMake的最小版本号,通过cmake --version命令查到下载的CMake版本号为4.2.1
cmake_minimum_required(VERSION 4.2)

# project:定义工程名称(这个名称随意,但是定下来了就不能改变了),并可指定工程的版本、支持的语言(默认情况支持所有语言)、工程描述、web主页地址,如果不需要这些都是可以忽略的,只需要指定出工程名字即可。
project(HELLOWORLD VERSION 1.0)

# add_executable:告诉CMake,要生成的可执行文件是什么,需要用到哪些源文件来编译和生成这个可执行文件,这里的可执行程序名和project中的项目名没有任何关系,源文件可以是多个,如有多个可用空格或;间隔
add_executable(helloworld helloworld.c hello.c world.c)

上面这三条指令就是一个最简单的CMakeLists.txt,下面就可以执行 cmake命令生成项目了:

1
2
3
4
# 注意,下面这里只是演示,实际一定要把项目建立在全英文目录下面
cmake E:\M. 尚硅谷_嵌入式资料\Cmake_Example\helloworld
# 注意,也可以使用cd命令进入CMakeLists.txt所在的文件夹中,这样就可以用 . 代替CMakeLists.txt的地址
cmake .

可以看到,一下子生成了很多文件(这里我已经把工程移动到D盘下面了,保证全英文目录):

我的电脑上安装了Visual Studio,因此默认生成了Visual Studio的工程文件。

但是,可以看到生成的工程文件和源码混合到了一起,非常不便于代码的管理,所以我们要单独创建一个目录,将生成的构建文件保存到这个目录中,一般会将这个目录定义为build。然后进入到这个目录下面,执行cmake ..注意是两个点,这样所有的工程文件就在build目录下面了,源文件不受影响。

这样,我们就可以使用Visual Studio打开HELLOWORLD.sln了(注意:ALL_BUILDZERO_CHECK在打开项目后要关闭)。

上面使用的CMake默认的配置,我们可以使用下面的命令:

1
cmake -G

列出所有的生成器Generators,其中带*号的是默认生成器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
Generators
Visual Studio 18 2026 = Generates Visual Studio 2026 project files.
Use -A option to specify architecture.
Visual Studio 17 2022 = Generates Visual Studio 2022 project files.
Use -A option to specify architecture.
Visual Studio 16 2019 = Generates Visual Studio 2019 project files.
Use -A option to specify architecture.
Visual Studio 15 2017 = Generates Visual Studio 2017 project files.
Use -A option to specify architecture.
* Visual Studio 14 2015 = Deprecated. Generates Visual Studio 2015
project files. Use -A option to specify
architecture.
Borland Makefiles = Generates Borland makefiles.
NMake Makefiles = Generates NMake makefiles.
NMake Makefiles JOM = Generates JOM makefiles.
MSYS Makefiles = Generates MSYS makefiles.
MinGW Makefiles = Generates a make file for use with
mingw32-make.
Green Hills MULTI = Generates Green Hills MULTI files
(experimental, work-in-progress).
Unix Makefiles = Generates standard UNIX makefiles.
Ninja = Generates build.ninja files.
Ninja Multi-Config = Generates build-<Config>.ninja files.
FASTBuild = Generates fbuild.bff files.
Watcom WMake = Generates Watcom WMake makefiles.

可以看到,其中有MinGW生成器,我们可以使用下面的命令,来生成MinGW的工程,同样,为了不污染源代码,这里先新建了一个文件夹bulid_mingw:

1
$ cmake -G "MinGW Makefiles" ..

可以看到,生成了一个Makefile文件,这样在Windows系统就可以使用minGW中的make命令来直接生成目标文件,也就是可执行程序helloworld.exe。而在Linux系统下可直接使用make命令生成可执行程序。

这里有点要注意的是,minGW的make程序名字叫做minGW32-make,因此直接在此文件夹下的命令行中输入minGW32-make就可以生成helloworld.exe。双击即可运行。

此外,不使用minGW32-make命令,还可以使用cmake命令生成可执行文件,命令是cmake --build .

可以看到通过使用CMake生成目标文件,我们可以不用了解实际的构建系统的命令。各类不同的构建系统都可以使用统一的配置文件。这对跨平台开发程序非常方便