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;


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM