介绍
在windows平台上,由于平台API差异过大,一般为linux设计的项目(POSIX兼容)无法通过MSVC的编译,而是会报非常多的头文件错误。如果要修改,工程量将巨大。Windows平台上,主要有两个类POSIX兼容平台,可以在Windows系统上编译运行为Linux编写的程序(功能支持不完整)。
- MinGW Minimalist GNU for Windows: 是将GCC编译器和GNU工具链套件移植到Windows平台下的产物。
- LLVM/Clang for Windows: Clang编译器对Windows Target的适配。由于LLVM框架的结构,只需要开发Windows平台对应的后端,而不需要进行迁移。LLVM在Windows平台的后端主要采用Visual Studio的MSVC编译器。
cmake是一个跨平台项目编译工具,通过CMakeLists.txt文件,可以方便地管理项目文件,并灵活地组织编译。根据工具链的不同,编译结果可以应用于各个平台上。例如,Linux系统中,cmake可以编译出Makefile,并交给linux平台的make程序进行编译。
一个项目需要在Windows平台上编译,但是是面向linux编写的(Makefile),这时候就需要使用Windows平台上的工具链进行编译。但是,多文件项目管理复杂,一个一个文件进行编译较为繁琐,这时候,就可以使用cmake工具辅助进行编译。
笔者是VS Code重度依赖用户,所以在VS Code上利用cmake tools进行配置。当然也可以使用命令行或是cmake-gui进行配置,只不过cmake tools更加集成和方便。
安装Clang-CL & CMake
Clang-CL for MSVC可以在Visual Studio的组件中找到

CMake可以在官网下载,安装后注意检查PATH,是否添加cmake
CMake & Toolkits
我们应当明确几个编译概念:
- Build System 编译系统:又称为Generator 生成器,是编译工具根据规则编译、链接文件的系统,按照是否集成交互,可分为;
- IDE Build Tool Generators 用于IDE的Build System,生成的项目可以直接被IDE打开、编辑,例如Visual Studio Generators
- Command-Line Build Tool Generators,使用命令行进行编译构建,有编译工具链即可工作,不需要IDE支持,例如,
Make构建系统(即Linux中使用Makefile进行构建的系统),以及Ninja(一套更轻量的命令行构建系统,是CMake Tools 的默认构建系统)
- Build Toolkits 编译工具链:是直接参与编译、生成可执行文件的一系列工具,包括Compiler 编译器, Linker 链接器等。主流的工具链如下:
- GNU/GCC: GNU项目组的编译工具链,主要运用于Linux系统,其在Windows上的迁移版本称为
MingGW - LLVM/Clang:LLVM编译基础设施,采用模块化设计,前后端分离工作,能够很好地适配多种前端语言和后端平台,是越来越流行的编译工具链
- Visual C++:微软开发的C/C++编译工具链,集成在Visual Studio上,主要用于Windows平台下的程序开发,即MSVC
- GNU/GCC: GNU项目组的编译工具链,主要运用于Linux系统,其在Windows上的迁移版本称为
编译系统使用编译工具链,按照开发者指定的编译规则进行程序的编译链接。那么,CMake属于哪里?CMake 属于更上一层的编译工具,使用CMake,可以生成任何一种适配的Build System所需要的规则,然后再调用这些Build System进行程序编译。
配置 cmake toolkits
在VS Code中,安装插件CMake Tools,并在项目目录中创建CMakeLists.txt文件,插件被激活后,状态栏会显示CMake Toolkits, Build Variant, Build Target等信息。如果是第一次在项目中使用插件,Toolkits工具链会显示No Kit Selected,单击该按钮,出现选择框。

初次配置,点击Scan for kits,工具会自动扫描电脑上安装的工具链。
Clang for MSVC 对应有四条(名称已经被我修改,正常情况下还有版本信息),Build Target有x86和x64,命令行接口有GNU CLI和MSVC CLI。
接下来,检查工具链配置参数,Ctrl+Shift+P,打开Command Palette,输入cmake kits -> 编辑用户本地CMake 工具包,这会打开一个json文件。

部分配置如下:
{
"name": "Clang 14.0.5 (GNU CLI) for MSVC (VS Community 2022 Release - x86)",
"visualStudio": "8b689476",
"visualStudioArchitecture": "x86",
"compilers": {
"C": "C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\VC\\Tools\\Llvm\\bin\\clang.exe",
"CXX": "C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\VC\\Tools\\Llvm\\bin\\clang.exe"
}
},
{
"name": "Clang 14.0.5 (MSVC CLI) for MSVC (VS Community 2022 Release - x64)",
"visualStudio": "8b689476",
"visualStudioArchitecture": "x64",
"preferredGenerator": {
"name": "Visual Studio 17 2022",
"platform": "x64",
"toolset": "ClangCL"
},
"compilers": {
"C": "C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\VC\\Tools\\Llvm\\x64\\bin\\clang-cl.exe",
"CXX": "C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\VC\\Tools\\Llvm\\x64\\bin\\clang-cl.exe"
}
},
- 对于MSVC CLI,Scan kit默认配置为MSVC Generator,注意检查toolset,必须修改为
ClangCL,若为host=xxx,则仍将通过传统MSVC工具链编译,仍会遇到API不适配问题 - 对于GNU CLI,默认配置为Ninja Generator,是一套轻量级、高效率的命令行构建系统,也可以根据需要修改
preferredGenerator为MSVC工具链
编译与常用选项
状态栏选项

- Build Variant (构建变体,编译选项……XD, anyway):选择工具链的编译输出模式,常见的有
Debug调试模式(包含调试信息)、Release发布模式(去除调试信息,增加优化) - ToolKits 工具链:为项目选择编译工具链(跨平台项目使用交叉编译工具链)
- Build 编译:点击编译(Not install)
- Build Target:编译目标,选择编译哪个项目,默认为
[all]全部编译,但是速度很慢,注意更换 - Debug\Run:调试、运行,不多介绍
Command Palette 命令选项卡
使用命令选项卡可以进行更加完整的配置,常用的有两个:
- CMake Clean:清除编译文件
- CMake Install:进行编译安装,将按照
CMakeLists.txt指定的安装配置进行生成工具的安装
示例
在一个目录下,创建如下文件
G:.
│ CMakeLists.txt
├─include
│ hello_lib.h
├─lib
│ │ CMakeLists.txt
│ ├─include
│ │ hello_lib.h
│ └─src
│ hello_lib.c
└─src
hello.c
// hello.c
#include <Windows.h>
#include <stdio.h>
#include "hello_lib.h"
int main() {
printf("Hello World!\n");
DbgPrint("%s\n", "Hello World"); // defined in hello_lib
return 0;
}
// hello_lib.h
#include <Windows.h>
#include <stdio.h>
#include <debugapi.h>
#include <stdarg.h>
void DbgPrint(char* FormatStr, ...);
// hello_lib.c
#include "hello_lib.h"
void DbgPrint(char* FormatStr, ...)
{
char dbgout[1000];
va_list vaList;
va_start(vaList, FormatStr);
sprintf(dbgout, FormatStr, vaList);
OutputDebugStringA(dbgout);
va_end(vaList);
}
然后配置CMakeLists:
root
cmake_minimum_required(VERSION 3.0)
project(HELLO)
add_subdirectory(lib)
aux_source_directory(src src_dir)
add_executable(hello ${src_dir})
target_include_directories(hello PUBLIC ${PROJECT_SOURCE_DIR}/include)
target_link_libraries(hello PUBLIC hello_lib)
add_subdirectory增加子项目target_link_libraries链接库,hello_lib在子项目中定义
lib
cmake_minimum_required(VERSION 3.0)
project(HELLO_LIB)
aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/src src_dir)
add_library(hello_lib STATIC ${src_dir})
target_include_directories(hello_lib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
add_library(STATIC)添加静态库
最后,build,输出结果:
[build] hello_lib.vcxproj -> G:\C\Cmake Test\build\lib\Debug\hello_lib.lib
[build] hello.c
[build] hello.vcxproj -> G:\C\Cmake Test\build\Debug\hello.exe
[build] Build finished with exit code 0



















