在CMake与Conan中使用MSYS2 MinGW x64工具链编译Windows程序

GCC(GNU Compiler Collection)是一套功能强大的编译器集合,支持C、C++、Fortran等编程语言,是Linux上应用十分广泛的一款编译器。MinGW(Minimalist GNU for Windows)将GNU工具链移植到了Windows环境,可用于编译原生的Windows应用程序。MinGW包含了GCC编译器的Windows移植版本以及用于Windows平台的链接器、汇编器等工具。但是,原始版本的MinGW只能用于编译32位程序,不支持64位程序的编译。

Mingw-w64是原始MinGW的一个衍生版本,增加了64位工具的支持。在Mingw-w64的官方网站上提供了单独的安装器下载,但其提供的GCC版本较旧,截至2021年12月4日最高只提供GCC 8.1.0版本。

MSYS2是一个运行在Windows上的类Linux平台。其脱胎于并且类似于Cygwin,能够运行经过重新编译的Linux应用程序,并提供了Linux上常见的许多GNU工具。不同之处在于,MSYS2更专注于提供一个用于构建原生Windows应用程序的平台。MSYS2中提供了mingw-w64的较新版本,能够提供较新的GCC编译器。目前, 截至2021年12月4日已经提供了此时的最新版本GCC 11.2.0。

MSYS2中提供的MinGW64工具链不但能够用于编译Windows应用程序,其本身也可以与Windows上的其他工具配合使用。本文将介绍如何在CMake与Conan使用MSYS2中的MinGW64工具链和GCC编译器编译Windows应用程序。

准备MSYS2环境及MinGW

通过MSYS2官方网站下载并安装MSYS2之后,在开始菜单-MSYS2 64bit文件夹下将出现5个MSYS2环境的入口。这几个环境中包含了不同的编译工具链,可用于不同的开发用途。其中MinGW x64环境中的编译工具链适用于编译Windows原生64位应用程序,其编译结果能够在Windows中运行而不依赖MSYS2环境;类似地,MinGW x32适用于编译Windows原生32位应用程序。不同的MSYS2环境的具体区别可参见Environments – MSYS2

依此点击开始菜单-“MSYS2 64 bit”-“MSYS2 MinGW x64”进入MSYS2环境,输入以下命令,通过pacman包管理器安装GCC编译器和其他编译工具:

pacman -S --needed mingw-w64-x86_64-toolchain

按提示完成安装操作后,就已经能够在MSYS2环境中使用GCC编译器了。输入下列命令可查看GCC版本:

gcc --version
# 输出:
# gcc.exe (Rev2, Built by MSYS2 project) 11.2.0
# Copyright (C) 2021 Free Software Foundation, Inc.
# This is free software; see the source for copying conditions.  There is NO
# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

在Windows上使用MinGW x64工具链

在PowerShell中,将MSYS2 MinGW x64环境的bin目录,即“{MSYS2安装目录}\mingw64\bin”添加到PATH环境变量。若MSYS2的安装目录为C:\msys64(这是默认的安装目录),则输入命令:

$env:PATH="$env:PATH;C:\msys64\mingw64\bin"

此时,可以直接在命令行中使用gcc命令。输入下列命令查看GCC版本,应得到跟之前看到的一样的结果:

gcc --version
# 输出:
# gcc.exe (Rev2, Built by MSYS2 project) 11.2.0
# Copyright (C) 2021 Free Software Foundation, Inc.
# This is free software; see the source for copying conditions.  There is NO
# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

新建一个文件夹,用于存放我们的测试代码,假设该文件夹名为cpptest。新建cpptest/main.cpp文件,添加以下内容:

#include <iostream>

using namespace std;

int main() {
    cout << "Hello, world!" << endl;
    return 0;
}

在PowerShell中导航到该代码文件夹,然后使用g++命令即可进行编译:

g++ main.cpp -o cpptest.exe

执行完命令后,会得到可执行文件cpptest.exe。在PowerShell中运行该文件可看到输出结果:

./cpptest.exe
# 结果:Hello, world!

CMake中使用MinGW x64工具链

假设Windows环境中已经安装了CMake,并且可以运行cmake命令,则此时我们可以使用CMake编译程序。在刚才的cpptest文件夹中新建CMakeList.txt文件,输入内容:

cmake_minimum_required(VERSION 3.18)

project(cpptest)
add_executable(${CMAKE_PROJECT_NAME} main.cpp)

在PowerShell中输入下列命令,将默认编译器设为GCC,然后进行编译:

$env:CC="gcc"
$env:CXX="g++"

mkdir build
cd build
cmake -G "MinGW Makefiles" ..
mingw32-make

编译完成后,会得到可执行文件build/cpptest.exe。在PowerShell中运行该文件可看到输出结果:

./cpptest.exe
# 结果:Hello, world!

Conan中使用MinGW x64工具链

在代码中使用第三方库

考虑一个调用了OpenBLAS线性代数库的程序。将cpptest/main.cpp的内容改为:

#include <iostream>
#include <cblas.h>

using namespace std;

int main()
{
  int i = 0;
  double A[6] = {1.0, 2.0, 1.0, -3.0, 4.0, -1.0};
  double B[6] = {1.0, 2.0, 1.0, -3.0, 4.0, -1.0};
  double C[9] = {.5, .5, .5, .5, .5, .5, .5, .5, .5};
  cblas_dgemm(CblasColMajor, CblasNoTrans, CblasTrans, 3, 3, 2, 1, A, 3, B, 3, 2, C, 3);
  for (i = 0; i < 9; i++)
    cout << C[i] << ' ';
  cout << endl;
  return 0;
}

用Conan安装第三方库

假设Windows环境中已经安装了Conan包管理器,并且可以运行conan命令,则可以通过Conan包管理器安装需要的第三方库。这里,我们安装线性代数库OpenBLAS。在cpptest文件夹中新建conanfile.txt文件,输入内容:

[requires]
openblas/0.3.17

[options]
openblas:build_lapack=True

[generators]
cmake_find_package

接下来,在PowerShell中为MinGW工具链新建一个Conan profile。在之前的步骤中,环境变量CCCXX已经被设置为了GCC编译器,此时Conan将能够自动识别到GCC编译器的默认配置。通过以下命令创建一个新的profile:

conan profile new mingw64 --detect

根据提示将C++运行库改为libc++11:

conan profile update settings.compiler.libcxx=libstdc++11 mingw64

在PowerShell中(此时工作目录应为cpptest/build文件夹),输入以下命令,使用Conan安装依赖项:

conan install --profile mingw64 --build=missing ..

Conan将会调用GCC编译器编译该第三方库。我们可以注意到,Conan还利用GCC中的Fortran编译器编译了OpenBLAS中的Fortran代码。

在CMake中完成编译

cpptest/CMakeLists.txt的内容改为:

cmake_minimum_required(VERSION 3.18)

project(cpptest)
add_executable(${CMAKE_PROJECT_NAME} main.cpp)

find_package(OpenBLAS)
target_link_libraries(${CMAKE_PROJECT_NAME} OpenBLAS::OpenBLAS)

CMAKE_MODULE_PATH设置为当前目录(cpptest/build),则CMake的find_package命令能够利用Conan在当前目录下生成的FindOpenBLAS.cmake文件查找OpenBLAS的安装。输入以下命令更新CMake配置并完成编译:

cmake -DCMAKE_MODULE_PATH:PATH=$(pwd) ..
mingw32-make

此时,可以运行编译完成的可执行文件:

./cpptest.exe
# 输出:
# 11 -9 5 -9 21 -1 5 -1 3

总结

将MSYS2 MinGW x64环境的bin目录添加到PATH环境变量后,可以在Windows环境中直接使用GCC等编译工具。将环境变量CCCXX分别设置为gccg++之后,Conan和CMake能够自动识别GCC编译器并将其作为默认编译器。使用MSYS2 MinGW x64环境中的GCC编译器能够生成可直接在Windows上运行的原生可执行文件。