LinuxWindows
图片来源

Linux to Windows代码移植技术路线

MinGW

MinGW/MinGW-W64是用Windows原生系统API实现的,在Windows上运行的GCC编译工具链,可以编译出Windows原生应用程序。

MinGW编译工具链的生态位和微软官方的MSVC类似。

优点

  • MinGW编译出的程序有能力直接在Windows系统中运行,不依赖外部库文件,并且运行效率很高。

缺点

  • MinGW工具链遵循Windows系统的ABI,有些定义与行为和Linux系统不一致。如long数据类型的字节长度。
  • MinGW不支持许多Linux的系统头文件与系统调用,需要修改代码,把Linux系统调用翻译为Windows系统调用。

注意事项

MinGW和MSVC / VS依赖的C标准库相同,均为MSVCRT.DLL / UCRT.DLL。这意味着

  • 使用微软的MSVC或VS构建C/C++程序时,可以直接链接MinGW构建的C库。
  • 使用MinGW构建C/C++程序时,可以直接链接MSVC或VS构建的C库。

MinGW和MSVC / VS依赖的C++标准库不同,且两者的函数符号命名方式不一致,这意味着

  • 使用微软的MSVC或VS构建C++程序时,不能链接MinGW构建的C++库。
  • 使用MinGW构建C++程序时,不能链接MSVC或VS构建的C++库。

代表项目

  • MSYS2
    • https://www.msys2.org/
  • MinGW-W64
    • https://www.mingw-w64.org/

Cygwin

从概念上来说,Cygwin是一个在Windows上运行的POSIX环境(可以理解为类Linux环境)。Cygwin为用户提供了各种POSIX系统调用和系统头文件,用户可以像使用Linux系统一样使用Cygwin。

从实现上来说,Cygwin库提供了一个中间层,用来把POSIX系统调用翻译成Windows系统调用。

传统的Linux发行版由“Linux系统内核”与“发行版定制的外围软件”这两部分组成。某种程度上,也可以把Cygwin理解为一个特别的Linux发行版,它的内核为“被中间层包裹的Windows内核”,外围软件为“Cygwin定制的外围软件”。

优点

  • Cygwin提供了一个POSIX兼容的环境,因此Linux代码无需经过太多修改,即可在Cygwin中进行编译。
  • 不同于MinGW,Cygwin使用LP64数据模型。long类型大小为8个字节,和Linux系统保持一致。

缺点

  • 编译出的可执行文件必须动态依赖于Cygwin动态库(作为中间层翻译)。
  • 由于引入了中间层,编译出的可执行文件运行效率低下。
  • Windows的多线程/进程实现逻辑与Linux有很大差别,使用Cygwin编译出的多线程/进程程序,运行时可能会出现问题。

注意事项

程序无法同时链接到Cygwin动态库与 MSVCRT.DLL / UCRT.DLL,二者互斥。这意味着

  • 你使用Cygwin开发的程序库,只能用于同样基于Cygwin开发的程序,不能被MinGW / MSVC / VS开发的程序使用。

代表项目

  • Cygwin
    • https://www.cygwin.com/
  • MSYS2(其中的MSYS环境)
    • https://www.msys2.org/

模拟器/虚拟机

通过动态二进制翻译技术,模拟出指定架构的处理器的行为。

优点

  • 项目可以在Linux系统中事先构建好。项目程序运行时,只需要为模拟器/虚拟机提供构建好的Linux原生二进制文件与其所需的运行时环境。

缺点

  • 不支持某些系统调用或指令。
  • 运行效率较低。
  • 该技术路线较为复杂,涉及环节多,不稳定因素多。

代表项目

  • QEMU(在MSYS2中安装与运行)
    • https://www.qemu.org/
    • https://packages.msys2.org/base/mingw-w64-qemu
  • jart/blink(在Cygwin中编译、安装与运行)
    • https://github.com/jart/blink

Cosmopolitan

Cosmopolitan项目包含了一套Cosmopolitan C标准库和一套Cosmocc编译工具链。其编译出的二进制文件符合POSIX标准,并且可以原生运行在多个硬件架构(AMD64 + ARM64)的多种平台上(Linux + Mac + Windows + FreeBSD + OpenBSD + NetBSD + BIOS)。Cosmopolitan让C语言拥有了“一次编译,到处运行”的能力。

优点

  • 只需要一套源码,使用Cosmopolitan编译出二进制文件,这些二进制文件可以在多个硬件架构和多个平台上原生运行。目前Cosmopolitan官方已经成功构建了Bash、Python、SQLite3、Vim、Lua等许多项目。
  • 遵循System V ABI使用LP64数据模型

缺点

  • 不支持某些系统调用或指令。
  • 该项目很年轻,仍在积极开发中。目前主要支持使用autotools作为构建工具的项目。

代表项目

  • jart/cosmopolitan
    • https://justine.lol/cosmopolitan/index.html
    • https://github.com/jart/cosmopolitan

代码移植技巧

对于MinGW技术路线,下面列举了一些常见的Linux系统头文件,以及它们的Windows实现或对应物。

使用的C库为微软实现的MSCVRT或UCRT,C++库为MinGW实现的libstdc++。此外,还需要使用到Windows的系统API。

微软官方 UNIX代码移植指南

UNIX Code Migration Guide | Microsoft Learn

sys/resource.h

  • https://github.com/JellyBrick/sys-resource-win
  • https://github.com/openvswitch/ovs/blob/master/include/windows/sys/resource.h
  • https://github.com/openvswitch/ovs/blob/master/lib/getrusage-windows.c

sys/mman.h

  • https://github.com/alitrack/mman-win32

dirent.h

  • https://github.com/tronkko/dirent

dlfcn.h

  • https://github.com/dlfcn-win32/dlfcn-win32
  • https://packages.msys2.org/package/mingw-w64-ucrt-x86_64-dlfcn

execinfo.h

  • https://github.com/ianlancetaylor/libbacktrace

性能对比

  • 硬件
    • 处理器: 英特尔 酷睿 i5-7300HQ @ 2.50GHz 四核四线程
    • 内存: 16GB DDR4 2400MHz ( 8GB + 8GB )
  • 操作系统
    • 名称:Microsoft Windows 11 家庭版 Insider Preview
    • 版本:10.0.27749 Build 27749
  • MSVC
    • VS构建工具版本:Visual Studio Build Tools 2022 17.12.3
    • MSVC版本:MSVC v143 - VS 2022 C++ x64/x86 build tools
  • WSL2 Ubuntu 20.04.2 LTS
    • 内核版本(uname -r):5.15.167.4-microsoft-standard-WSL2
    • GCC版本(gcc --version):9.4.0
  • MSYS2 UCRT64
    • 内核版本:3.5.4-0bc1222b.x86_64
    • GCC版本:14.2.0
  • Cygwin
    • 内核版本:3.4.9-1.x86_64
    • GCC版本:11.4.0

google/benchmark

  • 项目链接:https://github.com/google/benchmark
  • 测试时的提交节点:d5fad6b
  • 依赖:CMake >= 3.10
# 克隆最新的仓库
git clone https://github.com/google/benchmark.git

# 进入项目的根目录
cd benchmark

# 创建构建目录"build/"
cmake -E make_directory "build"

# 配置项目的CMake参数;下载依赖;生成构建系统的相关文件(如Makefile)
cmake -E chdir "build" cmake -DBENCHMARK_DOWNLOAD_DEPENDENCIES=on -DCMAKE_BUILD_TYPE=Release ../
# 对于MSYS2 UCRT64环境,在下一步构建时,可能会触发GCC的"maybe-uninitialize"提示。若要顺利进行构建,请执行以下被注释掉的命令,将BENCHMARK_ENABLE_WERROR设置为off
# cmake -E chdir "build" cmake -DBENCHMARK_DOWNLOAD_DEPENDENCIES=on -DCMAKE_BUILD_TYPE=Release -DBENCHMARK_ENABLE_WERROR=off ../

# 进行多线程构建,生成Release版本的二进制文件
cmake --build "build" --config Release -j 4

# 运行一系列测试,观察测试是否成功,观察完成测试所需的时间
cmake -E chdir "build" ctest --build-config Release

冷启动连续运行10次的耗时记录(单位:秒)

MSVCWSL2 Ubuntu 20.04MSYS2 UCRT64Cygwin
45.6712.1324.7323.06
43.5911.6023.15FAILED**
FAILED*11.6224.5624.51
44.0011.6919.1724.40
52.1111.7221.4722.54
45.7811.6418.0524.98
46.1511.6219.40FAILED**
45.0211.6817.9521.45
43.5711.64FAILED**23.62
43.8211.5218.1434.55

*FAILED: 62 - user_counters_tabular_test
**FAILED: 67 - complexity_benchmark

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐