Silentdoer

导航

Rust交叉编译相关总结

【GUI程序最好还是在各个平台编译,跨平台编译一大堆问题(我这边是报错了),源码跨平台也很不错了(而且如果是Windows,最好是在win7编译,这样能支持win8和10,而在win10编译的在win7和8可能运行不了),可以装虚拟机专门用于多平台编译】

通过命令查看支持哪些OS和CPU架构

rustc --print target-list | pr -tw100 --columns 3

 

toolchain和target分别是,toolchain是交叉编译所需的“编译工具”,而target则是编译到目标平台所需的“库文件”,

比如Ubuntu默认的target是gnu的,依赖glibc,但是其他Linux系统未必是glibc是基础库,但是可以用同一套toolchain(编译器之类的),因此只需要添加target即可;

而交叉编译到Windows,则Linux的编译器是没有这个能力的,因此需要添加Windows平台的toolchain(有部分tool官方没有实现还得添加第三方的tool),然后再添加target。

 

注意,如果Windows选择的是msvc而非gnu,那么哪怕是最简单的hello world也必须要安装visual studio(主要是需要它携带的toolchain【linker等】)

 

通过ldd命令可以查看编译出来的程序是否依赖动态链接库:

1.先普通编译,比如cargo build --release(没有--release则是编译在debug目录)

2.通过ldd命令查看:ldd target/release/bin-name(bin-name是编译的可执行程序名字)

可以看到类似这样的输出:

    linux-vdso.so.1 (0x00007ffd488b6000)
    libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007ff9c19e6000)
    librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007ff9c17de000)
    libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007ff9c15bf000)
    libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007ff9c13a7000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007ff9c0fb6000)
    /lib64/ld-linux-x86-64.so.2 (0x00007ff9c1e1f000)

说明是依赖了各类库的;

3.现在我们通过安装musl-libc工具链(比glibc【gnu-libc】要更轻量级)

rustup target add x86_64-unknown-linux-musl(可以加--toolchain=stable,但是默认是stable,也可以安装nightly的)【可以用rustup show查看安装了哪些工具链,可以看到stable-x86_64-unknown-linux-gnu是默认的工具链】

【注意,目前PC的话大多处理器架构都是x86_64的,如果目标运行机器不是这个架构的需要做出调整,Linux可以通过arch命令查看处理器架构,Windows通过systeminfo查看,而且据说x86_64,x64,AMD64是同一个架构】

接着通过cargo build --release --target=x86_64-unknown-linux-musl编译出来后在target里会有个x86_64-unknown-linux-musl目录,里面又根据--release有debug和release目录;

接着我们再通过ldd命令查看在x86_64-unknown-linux-musl里的可执行程序,发现它不再依赖glibc这些库了【不是动态可执行文件(即静态可执行文件)】(程序大小大了一些,但多的不是很多);

一、在Ubuntu下编译Windows10的程序

1.rustup toolchain install stable-x86_64-pc-windows-gnu【用msvc的有问题,我这边编译失败】

2.rustup target add x86_64-pc-windows-gnu --toolchain=stable

3.安装linker:sudo apt install mingw-w64(ubuntu是这个命令,如果是其他Linux系统可以通过搜索关键字mingw-w64,然后描述是Development environment targeting 32- and 64-bit Windows的基本上就是了)

4.在项目根目录创建.cargo目录,然后创建.cargo/config文件,在config文件里写:【注意,也可以全局配置,即~/.cargo/config,这里可以配置多个target.xxx和其相关的linker,比如这里还可以配置一个MacOS的】

[target.x86_64-pc-windows-gnu]
linker = "x86_64-w64-mingw32-gcc"
ar = "x86_64-w64-mingw32-gcc-ar"

也可以指定绝对路径:

linker = "/usr/bin/x86_64-w64-mingw32-gcc"
ar = "/usr/bin/x86_64-w64-mingw32-ar"

5.cargo build --release --target=x86_64-pc-windows-gnu,然后在target目录里有x86_64-pc-windows-gnu目录里有release目录可以找到对应可执行文件;

x86_64-pc-windows-gnu的程序用ldd查看也是不依赖动态库的;

二、在Ubuntu下编译Windows7的程序(和Ubuntu交叉编译到Windows10的步骤一致,该步骤生成的可执行程序可以直接运行在Win7上【gui之类的“高级”程序不一定】)

三、在Ubuntu下编译MacOS的程序(待测)

1.rustup toolchain install stable-x86_64-apple-darwin【如果没有用rustup是可以网上下载相关文件到指定位置的,具体可以再Google一下】

2.rustup target add x86_64-apple-darwin --toolchain=stable

3.执行命令安装Mac OS跨平台编译工具链:

git clone https://github.com/tpoechtrager/osxcross
cd osxcross
wget -nc https://s3.dockerproject.org/darwin/v2/MacOSX10.10.sdk.tar.xz
mv MacOSX10.10.sdk.tar.xz tarballs/
UNATTENDED=yes OSX_VERSION_MIN=10.10 ./build.sh

(暂时废弃,这里提示clang依赖冲突。。)

四、在Ubuntu下编译至其他Linux的程序【这里可以使用musl-libc将它内嵌到程序里实现跨多个平台的Linux程序(glibc是绝对路径,也可以在目标机器上安装glibc)】

1.rustup target add x86_64-unknown-linux-musl【下载x86_64任意版本Linux musl-libc库工具链】

2.cargo build --release --target=x86_64-unknown-linux-musl【如果依赖了openSSL还需要一些额外的配置】

3.用命令测试一下生成的可执行文件在目标机器、平台上是否可以运行:cargo test --target x86_64-unknown-linux-musl【最好还是复制到目标机器、平台运行一下看看。。(我这边test ubuntu到Windows的交叉编译的exe是失败,然后直接在Windows上跑是OK的)】

4.还要用ldd看下是否有依赖

五、在Windows10下编译Linux的程序(待试)

六、在Windows10下编译为Windows7的程序(跨系统的程序一般和是否是release模式无关,不过调试完毕最好还是生成release的可执行程序比较好)

1.首先需要在项目根目录下创建.cargo/config文件,在文件里添加:

[target.x86_64-pc-windows-msvc]
rustflags = ["-C", "target-feature=+crt-static"]

上面的配置就是弄静态编译用的,否则Windows下编译好的程序,由于依赖了动态链接库,把它弄到另一个Windows10或Win7下就不能运行了。

【但是注意,即便配置了上面的东西,对于一些程序换到另一个系统运行的时候仍然会出现缺失依赖的情况(主要是系统级的依赖库,rust不会将它们链接进来【而且由于Windows很多dll是C++写的,也可能是做不到对它们静态编译,毕竟rust ffi只能针对部分C++】)。。比如iced GUI程序(自己用cygcheck【Windows版ldd】查看了下还是依赖了dll库,比如依赖了这些库:

 C:\Windows\system32\ADVAPI32.dll
    C:\Windows\system32\msvcrt.dll
      C:\Windows\system32\ntdll.dll
      C:\Windows\system32\KERNELBASE.dll
    C:\Windows\system32\SECHOST.dll
      C:\Windows\system32\RPCRT4.dll
    C:\Windows\system32\KERNEL32.dll
  C:\Windows\system32\COMCTL32.dll
    C:\Windows\system32\GDI32.dll
    C:\Windows\system32\USER32.dll
      C:\Windows\system32\win32u.dll
  C:\Windows\system32\D3DCOMPILER_47.dll
    C:\Windows\system32\CRYPTSP.dll
  C:\Windows\system32\dwmapi.dll
  C:\Windows\system32\ole32.dll
    C:\Windows\system32\combase.dll
      C:\Windows\system32\bcryptPrimitives.dll
  C:\Windows\system32\SHELL32.dll
  C:\Windows\system32\UxTheme.dll

不过可以看到,它们都是系统库,所以换成另一个同系统运行是没问题的(我在Windows10下编译,换成另一台没装vs2017和rust的win10可以运行,但是换成win7就不行)

也可以先通过cygcheck命令找出依赖了哪些库,然后把这些库复制到可执行程序同级目录然后再在win7里应该也是可以的(我这边用于测试的程序由于依赖库又依赖了其它库所以不行(不过可以试着网上找缺失的dll放到程序所在目录【如果知道原来是来自哪里,则最好是放在对应的目录,比如System32目录,不知道的情况下放程序所在目录】)【不需要复制所有的依赖库,毕竟win7和win10有部分系统库还是一样的】【后面我用360来安装了所需的依赖库,程序可以打开了,但是最终还是执行失败,所以最好还是在同一个系统里编译比较好(控制台程序基本上不用)】)

)】

注意,如果程序编译好了却不能运行正常(假设不是代码逻辑问题),做成静态编译可能就能成功了(或者是切换为release就成功了,反正有点玄学),我这边用iced写的gui程序就是,debug的程序运行不正常,但是release模式的却可以;

2.安装Visual Studio 2017【vs2015或2013有部分程序没法编译成功【应该是因为DX12的原因】(但是vs2017编译的程序兼容性不好,GUI程序哪怕后端选了OpenGL编译后的仍然不能在win7上工作,所以最好还是用vs2013(至少C++部分,其他版本vs的就不要装c++模块了),对于部分不能编译的再考虑vs2017)】,在安装界面勾选工作负载下的Windows类别下的使用C++的桌面开发这一项(当然还可以勾选更多)【安装好后最好重启下电脑】

3.上面是msvc的,还可以用gnu的,需要先https://sourceforge.net/projects/mingw-w64/files/下载MinGW压缩包(注意下载最新的,不是上面所谓的latest,目前最新的是https://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting%20Win64/Personal%20Builds/mingw-builds/8.1.0/threads-posix/seh/x86_64-8.1.0-release-posix-seh-rt_v6-rev0.7z/download这个,可以参考:https://www.cnblogs.com/qq67579722/p/12897819.html),然后解压到某目录,配置MinGW的bin目录到Path环境变量里(我这边是R:/mingw64/bin,注意MinGW如果下载了多个版本,只能有一个版本的bin添加到path目录,否则可能有问题【而且要注意其他程序里是否也有mingw子目录配置到了Path,比如Git安装后就会,要先把它从Path删掉重开console,可以用echo %Path%查看Path变更是否生效,build后用cygcheck检查下看有没有依赖不合理的dll】),注意配置了Path需要重开终端,否则是读取不到的,可以输入g++.exe测试一下看当前console是否有mingw64/bin的Path,而且配置了mingw64/bin是可以不配置.cargo/config的linker,ar的(但是Path必须配置),接着执行:cargo build --release --target=x86_64-pc-windows-gnu就能顺利编译了【比msvc的大了好多倍。。】(不过即便是gnu编译出来的GUI程序【自己用的iced】也还是没法在win7上跑【自己在Windows10编译的】,蛋疼。。);【目前而言经过测试用GNU+MinGW64编译的程序不仅比msvc的大(而且可能也更慢),而且该依赖的系统库一个不少,还多依赖了一些MinGW64的dll(而且是配置了静态编译参数【除非gnu的静态编译参数不是这么配置,或者就是mingw库也无法静态编译到程序里】),所以还是老老实实用msvc的吧,GUI程序不能跨win10,win7就算了,在win10,win7各编译一遍(Windows版的MinGW方案不好用,但是可以考虑用win10的Linux子系统来实现,或者用MSYS2(类似一个Linux终端))】

【在Windows下用gnu哪怕静态编译一个hello world也是会依赖系统依赖库(msvc的反而依赖的更少一些),而在Ubuntu里交叉编译到Windows平台,编译出来的hello world程序也一样会依赖系统库。。】

七、在Windows10下编译为MacOS的程序(待试)

八、Windows7系统下编译Windows7、Windows10的程序(8没系统就不测了)

【控制台程序一般是没问题的,测下iced的GUI程序是否可以运行,如果win10,win7都可以运行,那么下次Windows10也安装vs2013好了(2013,2012都不行)】

1.下载visual studio2013安装,注意如果你的win7的IE是8它会不允许你安装visual studio2013,解决办法可以是先关闭visual studio2013安装程序,然后在桌面新建1.bat文件,里面填写:

@ECHO OFF
:IE10HACK 
REG ADD "HKLM\SOFTWARE\Wow6432Node\Microsoft\Internet Explorer" /v Version /t REG_SZ /d "9.10.9200.16384" /f 
REG ADD "HKLM\SOFTWARE\Wow6432Node\Microsoft\Internet Explorer" /v svcVersion /t REG_SZ /d "10.0.9200.16384" /f 
REG ADD "HKLM\SOFTWARE\Microsoft\Internet Explorer" /v Version /t REG_SZ /d "9.10.9200.16384" /f 
REG ADD "HKLM\SOFTWARE\Microsoft\Internet Explorer" /v svcVersion /t REG_SZ /d "10.0.9200.16384" /f 
GOTO EXIT
:REVERTIE 
REG DELETE "HKLM\SOFTWARE\Wow6432Node\Microsoft\Internet Explorer" /v svcVersion 
REG DELETE "HKLM\SOFTWARE\Microsoft\Internet Explorer" /v svcVersion 
REG ADD "HKLM\SOFTWARE\Wow6432Node\Microsoft\Internet Explorer" /v Version /t REG_SZ /d "8.0.7601.17514" /f 
REG ADD "HKLM\SOFTWARE\Microsoft\Internet Explorer" /v Version /t REG_SZ /d "8.0.7601.17514" /f 
GOTO EXIT
 
:EXIT

保存后以管理员权限执行,然后再次打开visual studio2013就可以安装了;

2.安装vs2013里必需勾选C++相关的内容

3.接下来就可以直接cargo build来编译项目了(注意有部分项目vs2013没法链接【应该是gui程序默认用了DX12导致的】,需要vs2017以上)

4.我这边测试是可以直接运行在win10上(【但是纯净版的复制上去一运行就自动关闭了。。(在朋友那有更新过的win10系统再测试一下【之前测试是OK的】),win7编译出的复制到刚装的win7上一打开也是关闭了,也没有应用日志,不知道什么原因】哪怕是gui程序,不过我gui程序后端是OpenGL而非DirectX11或12【不是游戏的话就用OpenGL,各个平台兼容性都比较好】)

【控制台程序则一点问题都没有,所以GUI程序最好还是不要跨平台编译】

八、编译为wasm程序【前提是这个应用程序是可以编译为wasm的程序】

1.rustup target add wasm32-unknown-unknown【只需要执行一次】

2.cargo build --target=wasm32-unknown-unknown【可以加--release】

3.cargo install wasm-bindgen-cli【只需要执行一次,类似安装程序一样,过程有点久】

4.第三步好了后就可以用wasm-bindgen命令了,在项目根目录输入:wasm-bindgen target/wasm32-unknown-unknown/debug/demo-iced.wasm --out-dir ./wasm-dist --web【注意第二步已经生成了target/wasm32-unknown-unknown/debug/demo-iced.wasm,但第四步生成的wasm-dist目录里的才是最终的.wasm文件,还有一个加载wasm的js文件】

5.项目根目录生成了wasm-dist目录,里面有4个文件,两个ts文件可以删除,然后在wasm-dist目录创建index.html文件,里面写

<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="Content-type" content="text/html; charset=utf-8"/>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>WASM - Iced</title>
  </head>
  <body>
    <script type="module">
      import init from "./demo-iced.js";

      init('./demo-iced_bg.wasm');
    </script>
  </body>
</html>

注意上面的两个文件路径和名称不要写错了(都是执行上面命令生成的),还有就是index.html必须是以http开头的请求获取,而不能是file开头的方式,可以在VSCode里安装Live Server插件实现以http请求打开index.html;

posted on 2020-06-01 11:04  Silentdoer  阅读(7117)  评论(1编辑  收藏  举报