简体   繁体   English

使用 Clang 从 Linux 交叉编译到 Windows

[英]Cross-compiling from Linux to Windows with Clang

I am trying to cross-compile C applications from Linux (64 bit) to Windows (64 bit) using Clang.我正在尝试使用 Clang 将 C 应用程序从 Linux(64 位)交叉编译到 Windows(64 位)。 I read the page on cross-compilation , which wasn't too helpful.我阅读了关于 cross-compilation页面,这并没有太大帮助。

As a simple test, I have the following code in test.c :作为一个简单的测试,我在test.c有以下代码:

#include <stdio.h>

int main()
{
        puts("hello world");
        return 0;
}

My best guess so far is clang -o test -target x86_64-win64-?ABI? test.c到目前为止,我最好的猜测是clang -o test -target x86_64-win64-?ABI? test.c clang -o test -target x86_64-win64-?ABI? test.c . clang -o test -target x86_64-win64-?ABI? test.c However, I have no idea what ABI Windows 64 bit uses.但是,我不知道 ABI Windows 64 位使用什么。 When I run clang with the target triple x86_64-win64-abcdefg , it seems to compile fine--that is, it finishes without error and results in something that is a somewhat-valid binary.当我使用目标三元组x86_64-win64-abcdefg运行 clang 时,它似乎编译得很好——也就是说,它没有错误地完成并产生了一些有点有效的二进制文件。 That doesn't make any sense, considering abcdefg is definitely not a valid ABI.这没有任何意义,考虑到abcdefg绝对不是有效的 ABI。 The resulting binary is far too big for such a small program, and Windows seems to think it's a 16-bit program (???).生成的二进制文件对于这样一个小程序来说太大了,Windows 似乎认为它是一个 16 位程序 (???)。 Disassembling it reveals references to "linux" and "gnu", so it would seem Clang is not even trying to compile for Windows.反汇编它会显示对“linux”和“gnu”的引用,所以看起来 Clang 甚至没有尝试为 Windows 编译。

Targeting win32 ( x86_64-win32-???ABI??? ) results in the following error message:定位 win32 ( x86_64-win32-???ABI??? ) 会导致以下错误消息:

test.c:1:10: fatal error: 'stdio.h' file not found
#include <stdio.h>
         ^
1 error generated.

This error, if I'm not mistaken, is the result of it not knowing where to look for system files.这个错误,如果我没记错的话,是因为它不知道去哪里寻找系统文件。 I assume Clang does store Windows header files somewhere, since it claims to be able to cross-compile;我假设 Clang 确实在某处存储了 Windows 头文件,因为它声称能够交叉编译; but where?但是哪里? If it doesn't, is there somewhere I can download them?如果没有,有什么地方可以下载吗?

Is there a list of all the architectures, systems, and ABI's Clang supports somewhere?是否有所有架构、系统和 ABI 的 Clang 支持的列表? The list on the cross-compilation page is not comprehensive.交叉编译页面上的列表并不全面。

The page also suggests using -mcpu=... , but a warning suggests that is outdated.该页面还建议使用-mcpu=... ,但警告表明已过时。 Instead, as the warning recommends, I tried -mtune=x86_64 .相反,正如警告所建议的那样,我尝试了-mtune=x86_64 This seems to have no effect.这似乎没有效果。 Is this even necessary, considering the architecture is specified in the target triple?考虑到架构是在目标三元组中指定的,这是否有必要?

I have seen some literature that suggests I need lld , LLVM's experimental linker.我看过一些文献表明我需要lld ,LLVM 的实验链接器。 Is this the case?是这种情况吗? I have had some issues compiling lld, and would like to avoid it if possible.我在编译 lld 时遇到了一些问题,如果可能的话,我想避免它。

I've installed mobaxterm on my windows 10 machine. 我已经在我的Windows 10机器上安装了mobaxterm。 There is a free version. 有一个免费版本。 It provides an xserver. 它提供了一个xserver。 It contains an installation of cygwin and you can start a local terminal. 它包含cygwin的安装,您可以启动本地终端。 you just type: apt-get install clang and clang is ready to compile and finds stdio.h without complaining. 你只需输入:apt-get install clang和clang就可以编译并找到stdio.h而不会抱怨。

But if you intend to run the resulting executable not on mobaxterm/cygwin but inside windows itself, you need to compile with mingwin instead. 但是如果你打算不在mobaxterm / cygwin上运行生成的可执行文件,而是在windows本身内运行,你需要用mingwin编译。

Your best option to develop Window binaries using clang is Mingw-w64, as you need more than just a compiler to compile for another system.使用 clang 开发 Window 二进制文件的最佳选择是 Mingw-w64,因为您需要的不仅仅是一个编译器来为另一个系统编译。 You also need a linker for that system as well as libraries to link against, so basically you need an SDK for the platform you are targeting and Mingw-w64 comes with everything you require.您还需要该系统的链接器以及要链接的库,因此基本上您需要一个适用于您目标平台的 SDK,而 Mingw-w64 随附了您需要的一切。

https://www.mingw-w64.org/downloads/ https://www.mingw-w64.org/downloads/

You can install it on a Linux system or macOS system and cross compile or you can install it directly on a Windows system and compile natively, without the requirement to have anything like the SDK of Visual Studio (VS).可以安装在Linux系统或macOS系统上交叉编译,也可以直接安装在Windows系统上进行本地编译,不需要像Visual Studio(VS)的SDK之类的东西。 Actually the same code should compile with any installation of Mingw-w64 regardless of the system you are using for building it.实际上,无论您使用什么系统来构建 Mingw-w64,都应该使用任何安装的 Mingw-w64 编译相同的代码。

Please note that Mingw does not give you a POSIX API on Windows.请注意,Mingw 不会在 Windows 上为您提供 POSIX API。 You will have the standard C/C++ API available that every platform must support and for everything else, you have to use native Windows API just like you'd have to when developing software with VS.您将拥有每个平台都必须支持的标准 C/C++ API,而对于其他一切,您必须像使用 VS 开发软件时一样使用本机 Windows API。 As not everyone may understand what I've just said, here's an example:由于不是每个人都理解我刚才所说的,这里有一个例子:

You can use fopen() to open a file as that is a standard C API function that every platform supports.您可以使用fopen()打开文件,因为这是每个平台都支持的标准 C API 函数。 But you cannot use open() to open a file, as that is a POSIX function defined in unistd.h and this header doesn't natively exist on Windows (not unless you have installed a POSIX subsystem which is not even available for all Windows version).但是您不能使用open()打开文件,因为它是在unistd.h定义的 POSIX 函数,并且此头文件在 Windows 上并不存在(除非您安装了一个甚至不适用于所有 Windows 的 POSIX 子系统。版本)。

In Windows you have windows.h and instead of fopen() you can use the function CreateFile() , which despite its name does not always create a file, it can also open existing ones for reading, and then you will get a HANDLE that you need to pass to CloseHandle() once you are done with it (which is like close() on UNIX systems).在 Windows 中,您有windows.h ,您可以使用函数CreateFile()代替fopen() ,尽管它的名称并不总是创建文件,但它也可以打开现有文件进行读取,然后您将获得一个HANDLE完成后,您需要传递给CloseHandle() (类似于 UNIX 系统上的close() )。

If you would like to get a POSIX-like API on Windows with no requirement of users having to install one, so you can share the same code between your Windows and Linux projects, appropriate wrappers do exist for that but that is not related to the compiler or SDK you are using.如果您想在 Windows 上获得类似 POSIX 的 API,而无需用户安装一个,这样您就可以在 Windows 和 Linux 项目之间共享相同的代码,则确实存在相应的包装器,但这与您正在使用的编译器或 SDK。 These are just Windows libraries you are liking against and that implement some fraction of the POSIX API on top of the Windows API;这些只是您喜欢的 Windows 库,它们在 Windows API 之上实现了一部分 POSIX API; which sometimes comes with caveats.有时会有警告。 It's the opposite of Wine which implements most of the Windows API on top of POSIX and other native system APIs.它与 Wine 相反,Wine 在 POSIX 和其他本机系统 API 之上实现了大部分 Windows API。

So you see, what makes porting C/C++ code hard is not the language itself but the libraries that act as a layer between your code and the system below it, as they differ from system to system, even between POSIX or POSIX-like systems.所以你看,使移植 C/C++ 代码变得困难的不是语言本身,而是作为代码和它下面的系统之间的层的库,因为它们因系统而异,甚至在 POSIX 或类 POSIX 系统之间也是如此. There are fundamental differences between Linux, FreeBSD, and macOS, despite the fact that they share a lot of the same API, too. Linux、FreeBSD 和 macOS 之间存在根本差异,尽管它们也共享许多相同的 API。 And if you want to test your Windows binaries after the build, you either need a real Windows environment to do so or at least an emulated one like Wine does provide.如果你想在构建后测试你的 Windows 二进制文件,你要么需要一个真正的 Windows 环境来这样做,或者至少需要一个像 Wine 提供的模拟环境。

The question is a bit old, but I hope this answer will help someone else.这个问题有点老了,但我希望这个答案能帮助别人。

Hypothetically, what you need is a cross-compiler that runs on Linux but builds a Windows executable using Visual Studio provided headers and libraries.假设,您需要的是一个在 Linux 上运行但使用 Visual Studio 提供的头文件和库构建 Windows 可执行文件的交叉编译器。 The link you provided redirects you to this page which tells you how to generate one.您提供的链接会将您重定向到此页面,页面会告诉您如何生成一个。 Hypothetically, you can build LLVM version 7 like this:假设,您可以像这样构建 LLVM 版本 7:

cmake -G Ninja -H. -B../_bin \
    -DLLVM_ENABLE_PROJECTS="llvm;clang;lld" \
    -DCMAKE_INSTALL_PREFIX=/opt/llvm-win32 \
    -DLLVM_TARGETS_TO_BUILD=X86 \
    -DCMAKE_BUILD_TYPE=Release \
    -DCLANG_TABLEGEN=/mnt/data/projects/llvm-org/dl/clang-tblgen-7 \
    -DLLVM_TABLEGEN=/mnt/data/projects/llvm-org/dl/llvm-tblgen-7 \
    -DLLVM_DEFAULT_TARGET_TRIPLE=i686-windows-msvc \
    -DLLVM_TARGET_ARCH=i686 \
    -DLLVM_TARGETS_TO_BUILD=X86 \

You may have to tweak clang/lib/Driver/ToolChains/MSVC.cpp source file so the shell separator is changed from ;您可能需要调整clang/lib/Driver/ToolChains/MSVC.cpp源文件,以便将外壳分隔符从; to : because on Unix shells, colon is used for separating multiple paths in variable. to :因为在 Unix shell 上,冒号用于分隔变量中的多个路径。

One more thing.还有一件事。 LLD defaults to Windows 7 in COFF format. LLD 默认为 COFF 格式的 Windows 7。 You may either statically or creatively modify Configuration::MajorOSVersion and Configuration::MinorOSVersion in lld/COFF/Config.h if you like to compile for an older Windows.如果您想为较旧的 Windows 编译,您可以静态或创造性地修改lld/COFF/Config.h Configuration::MajorOSVersionConfiguration::MinorOSVersion Check Windows Versions for the correct version you like to support.检查Windows 版本以获取您喜欢支持的正确版本。 Perhaps, an environment variable OS_VER could carry this information.也许,环境变量OS_VER可以携带此信息。

But even then, that's just the first step.但即便如此,这也只是第一步。 You still would need Visual Studio installed somewhere.您仍然需要在某处安装 Visual Studio。 This is where LLVM/clang will look for even basic headers like stdio.h or libcmt.lib .这是 LLVM/clang 甚至会寻找像stdio.hlibcmt.lib这样的基本头文件的libcmt.lib Hypothetically, if you have a Visual Studio 6 or later installed somewhere you could use that.假设,如果您在某处安装了 Visual Studio 6 或更高版本,则可以使用它。 Just make sure to rename all the files and directories to small-case (again, because Linux).只需确保将所有文件和目录重命名为小写(再次,因为 Linux)。

After that, triggering the compiler is simple.之后,触发编译器很简单。 Something like:就像是:

export VCINSTALLDIR=/mnt/data/projects/VC98
__inc="${VCINSTALLDIR}/include"
__inc="${__inc}:${VCINSTALLDIR}/atl/include"
__inc="${__inc}:${VCINSTALLDIR}/mfc/include"
export INCLUDE=${__inc}

__lib="${VCINSTALLDIR}/lib"
__lib="${__lib}:${VCINSTALLDIR}/mfc/lib"
export LIB="${__lib}"

export OS_VER="4.10" # Windows 98

exec /opt/win32/bin/clang \
    -fms-compatibility \
    -fms-extensions \
    -fmsc-version=1200 \
    -fuse-ld=lld \
    $*

in a shell script will do.在shell脚本中就可以了。 The INCLUDE and LIB variables are honored by LLVM. LLVM 支持INCLUDELIB变量。 Save it as something like i686-windows-msvc6-cc and you are good to go.将其另存为i686-windows-msvc6-cc ,您就可以开始使用了。 Hypothetically, you can now invoke the compiler on your test source like:假设,您现在可以在测试源上调用编译器,例如:

i686-windows-msvc6-cc -o test.exe test.c

Then, boot back into Windows or load your VM and execute test.exe .然后,重新启动到 Windows 或加载您的 VM 并执行test.exe

Note this is all hypothetical because MSVC terms and conditions don't allow you to fool around with their SDK like this.请注意,这都是假设性的,因为 MSVC 条款和条件不允许您像这样玩弄他们的 SDK。 This could likely also be the reason why no one distributes a cross-compiler like this either.这也可能是为什么没有人分发这样的交叉编译器的原因。 You can of course, try this hypothetically for educational purposes.当然,您可以出于教育目的假设性地尝试此操作。 Your best options is to use the one generated with MinGW instead like Mecki suggested.您最好的选择是使用 MinGW 生成的那个,而不是像Mecki建议的那样。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM