Clang C++交叉编译器-从Mac OS X生成Windows可执行文件

Clang C++ Cross Compiler - Generating Windows Executable from Mac OS X

本文关键字:OS 生成 Windows 可执行文件 Mac C++ 编译器 Clang      更新时间:2023-10-16

我使用Clang编译器在Mac上使用Xcode创建了一个C++应用程序。

我想编译我的源文件来创建一个可以在windows机器上运行的可执行文件,但我无法让Clang为我生成一个可执行文件。

以下是我尝试过的:

clang++ -std=c++11 -stdlib=libc++ -arch x86_64 class1.cpp class2.cpp... -o executable.exe

这创建了一个可执行文件,但它不能运行(Windows给我一个错误,因为应用程序是16位的-不理解这一点-不能在64位上运行)

clang++ -std=c++11 -stdlib=libc++ -target i386-pc-win32 class1.cpp class2.cpp 

出于某种原因,每当我使用-target标志时,我都会收到一个错误,说明编译器找不到<iostream>标头,但在其他任何时候它都不会抱怨
我试过使用-Ipath/to/iostreamfolder/,但这并没有产生任何更好的结果

任何建议都很好!谢谢

我也尝试过'-triple x86-pc-win32'标志,但我收到了这个警告clang: warning: argument unused during compilation: '-triple x86-pc-win32'

以下是在Mac OS X上使用llvm/clang构建Hello World.exe的分步说明。

在Mac OS X上使用Clang/LLVM交叉编译Hello World for Windows

用自制软件安装llvm。这将包括clang和llvm链接器。

brew install llvm

您需要访问Visual Studio C++库和标头,这些库和标头可通过Visual Studio 2017在Windows 10虚拟机(VM)或Windows 10计算机上获得。在Window上安装Visual Studio,并通过Visual Studio安装程序包括以下"单个组件":

  • Windows通用CRT SDK
  • Windows通用C运行时
  • 用于UWP:C的Windows 10 SDK(X.X.X.X)++
  • VC++2017 vXXX工具集(x86、x64)
  • Visual C++2017 Redistributable Update
  • C++/CLI支持

从Mac上访问MSVC库和头文件。

  • (选项1)使用Windows虚拟机并在主机和来宾之间创建共享文件夹
  • (选项2)在Windows计算机上创建远程共享,并从Mac连接到它
  • (选项3)按照任何许可条款将库和标头复制到您的Mac

在llvm+MSVC安装中查找与以下内容相对应的特定目录:

// LLVM:
INCLUDES: /usr/local/Cellar/llvm/5.0.0/include
// MSVC:
INCLUDES: "C:Program Files (x86)Microsoft Visual Studio2017CommunityVCToolsMSVC14.11.25503include"
LIBS: "C:Program Files (x86)Microsoft Visual Studio2017CommunityVCToolsMSVC14.11.25503libx86"
// C Runtime Library (CRT):
INCLUDES: "C:Program Files (x86)Windows Kits10Include10.0.15063.0ucrt"
LIBS: "C:Program Files (x86)Windows Kits10Include10.0.15063.0ucrt"
// User-Mode Library (UM):
INCLUDES: "C:Program Files (x86)Windows Kits10Include10.0.15063.0um"
LIBS: "C:Program Files (x86)Windows Kits10Lib10.0.15063.0umx86"
// 'Shared' includes:
INCLUDES: "C:Program Files (x86)Windows Kits10Include10.0.15063.0shared"
// WinRT includes:
INCLUDES: "C:Program Files (x86)Windows Kits10Include10.0.15063.0winrt"
// Figure out your MSC 'version', e.g.
Visual C++ 2012 (11.0)   -->     MSC_VER=1700
Visual C++ 2013 (12.0)   -->     MSC_VER=1800
Visual C++ 2015 (14.0)   -->     MSC_VER=1900
Visual C++ 2017 (15.0)   -->     MSC_VER=1910

创建你的Hello World src:

// hello.cc
#include <cstdio>
int main(int argc, char* argv[]) {
  printf("Hello, World!n");
  return 0;
}

用clang编译:

clang -target i686-pc-win32 
  -fms-compatibility-version=19 
  -fms-extensions 
  -fdelayed-template-parsing  
  -fexceptions 
  -mthread-model posix 
  -fno-threadsafe-statics 
  -Wno-msvc-not-found 
  -DWIN32 
  -D_WIN32 
  -D_MT 
  -D_DLL 
  -Xclang -disable-llvm-verifier 
  -Xclang '--dependent-lib=msvcrt' 
  -Xclang '--dependent-lib=ucrt' 
  -Xclang '--dependent-lib=oldnames' 
  -Xclang '--dependent-lib=vcruntime' 
  -D_CRT_SECURE_NO_WARNINGS 
  -D_CRT_NONSTDC_NO_DEPRECATE 
  -U__GNUC__ 
  -U__gnu_linux__ 
  -U__GNUC_MINOR__ 
  -U__GNUC_PATCHLEVEL__ 
  -U__GNUC_STDC_INLINE__  
  -I/usr/local/Cellar/llvm/5.0.0/include 
  -I/c/Program Files (x86)/Microsoft Visual Studio/2017/Community/VC/Tools/MSVC/14.11.25503/include 
  -I/c/Program Files (x86)/Windows Kits/10/Include/10.0.15063.0/ucrt 
  -I/c/Program Files (x86)/Windows Kits/10/Include/10.0.15063.0/shared 
  -I/c/Program Files (x86)/Windows Kits/10/Include/10.0.15063.0/winrt 
  -c hello.cc -o hello.o

链接lld链接器,由clang:驱动

clang -fuse-ld=lld -target i686-pc-win32 -Wl,-machine:x86 -fmsc-version=1900 
  -o hello.exe hello.o 
  -L/external/code8-cc/cc/msvctoolchain/x86/lib/msvc 
  -L/external/code8-cc/cc/msvctoolchain/x86/lib/um 
  -L/code8-cc/cc/msvctoolchain/x86/lib/ucrt
  -nostdlib -lmsvcrt -Wno-msvc-not-found 

将hello.exe复制到您的Windows计算机或Windows虚拟机并在PowerShell中运行:

.hello.exe

若要生成64位版本,请更改为"-target x86_64-pc-win32"、"-Wl,-machine:x64",然后链接到x64库。

Clang原则上可以用作交叉编译器:与大多数编译器不同,Clang/LLVM在同一二进制文件中包含不同平台的组件(如代码生成程序、汇编程序和链接器)。

然而,在生产能力中尝试使用它时会遇到许多问题:

  • 您需要平台库和标头。要生成可在Windows上运行的可执行文件,您需要链接到的Windows标头和Windows库,如果您正在动态链接,请导入库,或者导入静态库进行静态链接。您应该能够从Visual Studio的安装中获得这些。

  • 许多C++功能,如名称篡改和RTTI支持,在Windows上并不完整。使用Clang在Windows上编译Windows时也会遇到同样的问题Windows C++的支持现在已经基本完成了。

  • LLVM项目包括lld链接器,它显然已经足够长了,可以在x86 Windows上自托管,因此可以作为跨平台链接器使用,但是lld还不是clang发行版的标准部分。默认情况下,OS X上的Clang仍然使用OS X平台链接器ld,Windows上的Clag也是如此(link.exe)。您需要获取lld并弄清楚如何与它链接,或者找到其他跨平台链接器。

  • clang驱动程序不是作为跨平台编译器驱动程序编写的。要运行跨平台编译,您可能需要做更多的实际操作。看看clang -###的输出:clang驱动程序为您构造该命令,但您可能需要手动执行与clang驱动相同的许多工作。由于clang在跨平台编译中得到的测试要少得多,您可能会遇到更多的错误。

  • Xcode对你没有任何帮助。它可以将clang配置为OS X或iOS版本,但您必须手动将跨平台版本配置为Windows版本。

我相对有信心,可以拼凑出一个基于LLVM的环境,在OS X或Linux上构建一个C"Hello,World"Windows exe,但Xcode还没有准备好在可能的目标平台列表中添加"Windows"项目。


如果你不是一个编译器开发人员,你最好把源代码复制到Windows机器上,然后用Visual Studio进行构建。如果你是或想成为一名编译器开发人员,那么一定要帮助Clang的交叉编译能力向前发展。我认为Clang通用驱动程序项目是令人兴奋的,我真的希望看到进展继续下去。


我已经成功地完成了相反的交叉编译:在Windows上编译一个Mac OS X可执行文件。这在小程序上很容易手动完成,即直接编译.cpp文件。

首先,Mac OS X开发工具附带"SDK",其中包含特定操作系统的所有系统库和头文件。这里最大的挑战是弄清楚如何将SDK转移到Windows,同时保留SDK中的所有符号链接。(出于某种原因,在Windows上创建符号链接需要更高的权限,所以在OS X上生成带有符号链接的tar.gz后,我不得不作为管理员在Windows上运行7zip来正确扩展存档。)

一旦SDK在Windows上可用,就有一个单独的标志来告诉clang在哪里获取所有的系统依赖项:-isysroot。这与-target标志相结合,就是我需要告诉clang如何为OS X生成完整的对象文件的全部内容。

对于链接,我手动使用了lld,因为编译器驱动程序似乎不支持使用lld的交叉链接。lld支持用于确定目标系统库的类似标志。

最后一步是简单地将生成的可执行文件复制到OS X机器上,启用执行权限(Windows不支持相同的文件权限,因此在构建时不会设置执行位)并运行结果。

考虑在Mac OS X上使用MinGW编译Windows二进制文件。以下是有关如何在Linux上执行此操作的说明:http://www.blogcompiler.com/2010/07/11/compile-for-windows-on-linux/

你必须将它们适应Mac OS X,你可能必须自己编译MinGW。

http://www.mingw.org

多亏了xwin项目,现在可以很容易地在Mac或Linux等其他平台上获得Windows头文件和库:

  1. 使用xwin安装头文件和库:
    export WINSDK_PATH="$HOME/winsdk"
    ./xwin --accept-license splat --preserve-ms-arch-notation --output "$WINSDK_PATH"
    
  2. 安装clang、clang-cl、lld,如果需要,还可以为OpenMP安装libomp。在Mac上,brew install llvm应该可以工作,在Debian/Ubuuntu sudo apt install clang lld libomp-13-dev clang-tools上。它也可以与conda:conda install clang llvm-openmp一起安装
  3. 使用clang-cl编译代码。Clang cl可以像Microsoft编译器cl.exe一样使用。C运行时库可以使用选项/MT静态链接(默认),也可以使用/MD动态链接(可能更适合大多数使用):
    # Create a program from C++ code
    clang-cl  --target=x86_64-pc-windows-msvc -fuse-ld=lld /winsdkdir "$WINSDK_PATH/sdk" /vctoolsdir "$WINSDK_PATH/crt" /MD hello.cpp -o hello.exe
    # Create a DLL from C code and use OpenMP, AVX2 and LTO ("/openmp", "/arch:avx2", "-flto")
    clang-cl --target=x86_64-pc-windows-msvc -fuse-ld=lld /openmp /arch:avx2 -flto /LD /winsdkdir "$WINSDK_PATH/sdk" /vctoolsdir "$WINSDK_PATH/crt" /MD dll_test.c
    # The same without clang-cl
    clang -o dll_test.dll 
      -target x86_64-pc-windows-msvc 
      -isystem "$WINSDK_PATH/crt/include" 
      -isystem "$WINSDK_PATH/sdk/Include/ucrt" 
      -isystem "$WINSDK_PATH/sdk/Include/shared" 
      -isystem "$WINSDK_PATH/sdk/Include/um" 
      -Xclang --dependent-lib=msvcrt 
      -fuse-ld=lld "-L$WINSDK_PATH/crt/lib/x64" 
      "-L$WINSDK_PATH/sdk/Lib/ucrt/x64" 
      "-L$WINSDK_PATH/sdk/Lib/um/x64" 
      -flto 
      -shared 
      -march=x86-64-v3 
      c_test.c
    

当使用clang而不是clang-cl时,添加-Xclang --dependent-lib=msvcrt会创建一个动态链接的二进制文件,如/MD