通過LLVM 在 Android 上運行 Swift 代碼

2021-01-09 開源中國

Swift 已經發布一年多了,蘋果承諾將在 2015 年底開源 Swift。這是非常棒的一件事情,但是我們現在可以在 Android 設備上運行 Swift 嗎?

Swift 編譯器

這都是由 Chris Lattner 設計的,很容易就可以發現 Swift 的編譯器是基於 LLVM 構建的。LLVM 是個編譯器基礎設施,利用了了一個可重定向編譯器的有趣概念。

也就是說,不是生成特定架構的機器代碼,LLVM 為一個虛擬機生成彙編代碼,然後轉換成中間代碼,適配架構需要的實際代碼。

模塊化的設計非常的好,因為允許高度代碼復用(前端和後端的共享優化)。更多關於 LLVM 的資料請看這裡。

適配不同的機器

在這一點上,你可能會想:

如果 LLVM 已經夠模塊化,那麼我們是否可以使用一個不同的後端,生成二進位代碼,適配 OS X,iOS 或者是 Android?

假設是可以的,我們來看看如何實現。

手動構建 Swift 代碼

如果使用 Xcode,系統會自動完成這些。我們現在需要手動編譯和連接一個簡單的 Swift "Hello world" :

// hello.swiftprint("Hello, world!");

構建對象文件:

$ $SDK/usr/bin/swiftc -emit-object hello.swift

hello.o 裡面到底有什麼:

$ nm hello_swift.o                 U __TFSSCfMSSFT21_builtinStringLiteralBp8byteSizeBw7isASCIIBi1__SS                 U __TFSs27_allocateUninitializedArrayurFBwTGSaq__Bp_                 U __TFSs5printFTGSaP__9separatorSS10terminatorSS_T_                 U __TIFSs5printFTGSaP__9separatorSS10terminatorSS_T_A0_                 U __TIFSs5printFTGSaP__9separatorSS10terminatorSS_T_A1_0000000000000140 S __TMLP_0000000000000100 S __TMaP_                 U __TMdSS                 U __TZvOSs7Process11_unsafeArgvGVSs20UnsafeMutablePointerGS0_VSs4Int8__                 U __TZvOSs7Process5_argcVSs5Int32                 U _globalinit_33_1BDF70FFC18749BAB495A73B459ED2F0_func6                 U _globalinit_33_1BDF70FFC18749BAB495A73B459ED2F0_token60000000000000000 T _main                 U _swift_getExistentialTypeMetadata                 U _swift_once

看吧,這非常有趣。Swift mangles symbols 看起來明顯有點像 C++。事實上,print 函數並沒有成為 _print symbol ,但是成為了更複雜的 symbol 的  __TFSs5printFTGSaP__9separatorSS10terminatorSS_T_ 列表。

同時也要求其他 symbols,主要是為了處理字符串轉換和內存處理。

無論如何,所有這些 symbols 已經在 libswiftCore.dylib 定義,也出現在 $SDK。我們現在要把這些信息給 linker:

$ ld -arch x86_64 -o hello hello.o     -L$SDK/usr/lib/swift/macosx     -lSystem -lswiftCore$ DYLD_LIBRARY_PATH=$SDK/usr/lib/swift/macosx ./helloHello, world!

是的,這個方法是可行的。

適配 Android

現在最大的問題是 SwiftCore 庫缺失。現在蘋果已經為 iOS,OS X 和 Watch OS 都提供了一個。但是,很明顯,並沒有提供 Android 版本。

但是,不是所有 Swift 代碼都要求 SwiftCore 庫,跟不是所有 C++ 代碼都要求 STL 一樣。所以只要使用 Swift 的子集,不需要 SwiftCore 的那部分,這問題就算解決了。

為了演示,我們先來一個簡單的:

// add.swiftfunc addTwoNumbers(first: UInt8, second: UInt8) -> UInt8 {  return first + second}

所以這過程基本分為 3 個步驟:

讓 Swift 編譯器生成一些 LLVM-IR

使用 LLVM 從中間表示的代碼生成 ARM ELF

使用 Android NDK 來生成一個二進位代碼,連接到已生成的對象文件

1. 讓 Swift 編譯器生成一些 LLVM-IR

在之前的步驟中,當運行 swiftc hello.swift,Swift 編譯器實際在幹兩件事情:

從 Swift 代碼中生成 LLVM 中間表示代碼

轉換 IR 為一些 x86_64 機器代碼,打包為一個 Mach-O 文件

這個實際上是非常常用的事例,所以編譯器可以一次性做完這些。但是我們想要生成一些 ARM ELF 文件 (在 Android 上使用的二進位格式文件)。

$SDK/usr/bin/swiftc  -parse-as-library # We don't need a "main" function  -target armv7-apple-ios9.0  -emit-ir  add.swift  | grep -v "^!" # Filter-out iOS metadata  > add.ll

注意:我們需要添加 "grep" 過濾器來移除一些  iOS 特定的元數據(Swift 編譯器加進去的) 。

2. 從 LLVM-IR 中生成一個對象文件

在這點上,我們需要 Android NDK。非常幸運的是已經包括了一個 LLVM 工具鏈,我們可以利用  llc (LLVM static compiler) :

$NDK/toolchains/llvm-3.5/prebuilt/darwin-x86_64/bin/llc  -mtriple=armv7-none-linux-androideabi  -filetype=obj  add.ll

非常棒,所以我們已經構建了一個 ARM ELF 對象文件!

3. 打包一個 Android 應用的對象文件

我們需要從 Java 中調用它,所以需要一個 JNI bridge。這使用 C 來編寫非常簡單:

// jni-bridge.c// Let's work around Swift symbol mangling#define SWIFT_ADD _TF3add13addTwoNumbersFTVSs5UInt86secondS0__S0_uint8_t SWIFT_ADD(uint8_t, uint8_t);jstring jni_bridge(JNIEnv * env, jobject thiz ) {  uint8_t a = 123;  uint8_t b = 45;  uint8_t c = SWIFT_ADD(a,b);  char result[255];  sprintf(result, "The result is %d", c);  return (*env)->NewStringUTF(env, result);}

最後,我們需要打包所有,變成一個共享庫:

$NDK_GCC/bin/arm-linux-androideabi-ld  add.o  jni_bridge.o  -shared # Build a shared library  -lc # We'll need the libc  -L$NDK/platforms/android-13/arch-arm/usr/lib

就是這樣!我們需要打包,在一個 Android 應用中分享對象文件,然後運行:

總結

這非常有趣,但是並沒有什麼用:

最後,很重要的一點,這個示例已經放到了 GitHub。

via romain.goyet.com

相關焦點

  • llvm學習第二站 - 什麼是llvm IR
    官網介紹:https://releases.llvm.org/11.0.0/docs/GettingStarted.html工具名稱工具用途llvm-ar‍歸檔器,創建靜態庫,用法和ar基本一致llvm-asLLVM assembler 彙編器,輸入是LLVM IR,輸出為
  • Android上玩玩Hook:Cydia Substrate實戰
    而「鉤子」的意思,就是在事件傳送到終點前截獲並監控事件的傳輸,像個鉤子勾上事件一樣。並且能夠在勾上事件時,處理一些自己特定的事件。如下圖所示:我們也知道,在Android系統中使用了沙箱機制,普通用戶程序的進程空間都是獨立的,程序的運行彼此間都不受幹擾。這就使我們希望通過一個程序改變其他程序的某些行為的想法不能直接實現,但是Hook的出現給我們開拓了解決此類問題的道路。當然,根據Hook對象與Hook後處理的事件方式不同,Hook還分為不同的種類,如消息Hook、API Hook等。
  • 15種快速技巧,提升Swift編碼能力
    考慮到抽象化,使用泛型可生成更為清晰的代碼,減少錯誤。如上文所示,通過選擇選項2,可編寫一個函數(相對於多個),處理幾種不同類型的輸入。4.通過十六進位代碼生成UIColor創建一個名為 UIColor+Extensions.swift的文件,包含以下代碼:import UIKitextension UIColor {convenience init(hex:Int, alpha: CGFloat = 1.0) {self.init(red: CGFloat
  • 寫下LaTeX代碼就要看結果?這款編輯器讓你「所見即所得」
    它通過代碼的形式,讓寫出來的報告和論文保持良好的格式,因此受到歡迎。LaTeX 有一個小小的缺點——寫好的 LaTeX 代碼並不能夠立刻表現為真實的排版效果。近日,GitHub 出現了一個新的項目,是一個名為 SwiftLaTeX 的可視化編輯器。該項目最大的亮點在於:你編寫的 LaTeX 代碼能夠立刻展示實際的效果,所見即所得。這個編輯器還是基於瀏覽器的,還支持雲文件存儲。
  • Package Swift
    Package.swift 使用在Swift 開發中替換 cocoaPod 的包管理器,簡稱 SPM,執行速度上速度更快,並且體檢最佳。
  • 2014 非常好用的開源 Android 測試工具
    AndroidJUnit4AndroidJUnit4 是一個讓 JUnit 4 可以直接運行在 Android 設備上的開源命令行工具。你可以在任意的模擬器示例或者設備上運行。Monkey 發送一個用戶事件的 pseudo-random 流給系統,作為你開發應用的壓力測試。
  • Android壓力測試Monkey工具
    本文引用地址:http://www.eepw.com.cn/article/201610/305869.htm一、 什麼是MonkeyMonkey是Android中的一個命令行工具,可以運行在模擬器裡或實際設備中。它向系統發送偽隨機的用戶事件流(如按鍵輸入、觸控螢幕輸入、手勢輸入等),實現對正在開發的應用程式進行壓力測試。
  • 手把手教程:如何從零開始訓練 TF 模型並在安卓系統上運行
    下載我的示例代碼並執行以下操作:1)通過命令行轉換$ tflite_convert \ $ --output_file=mymodel.tflite \ $ --keras_model_file=mymodel.h52)通過
  • Android P 行為變更
    針對所有運行在 Android P 上的應用 這些行為變更適用於所有在 Android P 平臺上運行的應用,無論它們是針對哪個 API 等級開發的。所有開發者都應該查看這些變更,並對其應用作出相應修改,從而正確支持這些變更 (若變更可適用於應用)。
  • com.android.systemui已停止是什麼意思 怎麼解決
    com.android.systemui已停止是什麼意思 怎麼解決 來源:www.18183.com作者:皮卡時間:2016-01-20 我們如果需要解決手機使用中出現com.android.systemui已停止運行的問題,那麼我們首先要搞清楚com.android.systemui
  • 基於Android的嵌入式Web伺服器設計
    在三網融合的大背景下,通過家庭網關實現外部網絡即電視網、電信網、網際網路與家庭內部電話、電視、電腦以及家庭電器設備的通訊,是當前家居智能化、現代化的重要發展趨勢。本文的主要內容是研究基於家庭網關的嵌入式系統,實現簡單實用的Web伺服器功能,為外部網絡提供一個方便快捷地訪問和控制家庭內部資源的平臺。
  • android藍牙相關框架專題及常見問題 - CSDN
    代碼來源於Android P,本文相關代碼:client:frameworks/base/core/java/android/bluetooth/*system/bt/binder/android/bluetooth/**.aidlservie:framework/base/services/core/java/com/android/server/BluetoothService.java
  • 谷歌為何要養蘋果的親兒子Swift?原來意在可微分編程
    用 PyTorch 時,你的代碼必須像用 Python 一樣命令式地運行,唯一不透明的情況是運行在 GPU 上的運算是異步式地執行的。這通常不會有問題,因為 PyTorch 對此很智能,它會等到用戶交互操作所依賴的所有異步調用都結束之後才會轉讓控制權。儘管如此,也還是有一些問題存在,尤其是在基準評測(benchmarking)等任務上。
  • Java程式設計師必備基礎:Java代碼是怎麼運行的?
    運行時創建對象 方法調用,執行引擎解釋為機器碼 CPU執行指令 多線程切換上下文 編譯 我們都知道,java代碼是運行在Java虛擬機上的。
  • Android系統APK文件詳解
    通過將APK文件直接傳到Android模擬器或Android手機中執行即可安裝。APK文件其實是zip格式,但後綴名被修改為apk,通過UnZip解壓後,可以看到Dex文件,Dex是Dalvik VM executes的全稱,即Android Dalvik執行程序,並非Java ME的字節碼而是Dalvik字節碼。
  • 360手機專家解密Android惡意軟體7大技術趨勢
    9月23日,在360公司主辦的2013年網際網路安全大會(ISC)上,手機安全專家劉敦俊介紹了Android惡意軟體的七大技術趨勢,指出未來移動安全形勢不容樂觀。值得警惕的是儘管Android智慧型手機通過包括遊戲、社交、購物、LBS等功能豐富的應用,為我們的生活帶來便利的同時,也給用戶帶來了極大的安全隱患。  首當其衝的問題就是垃圾簡訊、騷擾電話的泛濫,不僅直接影響著用戶的正常生活,隱藏其中的詐騙信息還使人們的財產安全處於危險之中。劉敦俊認為,通信安全是四大安全問題之中非常重要的一環,需要引起人們足夠的重視。
  • android啟動頁設計專題及常見問題 - CSDN
    ><FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent
  • 不用從零學android入門編程,這款傻瓜式開發工具,快速製作App
    過去要開發一款專業的APP軟體,只能通過程式設計師敲代碼製作。現在,不需要從零開始學android編程技術,任何人都可以輕鬆製作手機APP。國外的網際網路巨頭:比如谷歌的輕代碼 H5 應用開發工具——App Maker,微軟的PowerApps,就是通過拖拽式的進行應用開發。
  • 基於LLVM的內存計算
    雖然這些瓶頸很難克服,但Google研發的Tenzing技術裡面提出基於LLVM編譯框架實現動態生成代碼Codegen這個技術,並且通過這個技術基於MapReduce分布式框架下面的類SQL系統的性能也能接近商業收費並行資料庫的水準。
  • With語句,提高VBA代碼運行速度的方案
    適當節制自我的各種欲望,誰都逃不過時間的歷練,誰都是命運的行者,誰都是在人生的道路上一步一趨,把生活與工作打理好,不負年華。欲成大事者,必先修其身。欲修其身者,先正其心。小成靠智,大成靠德。身不修則德不立,德不立則無以成事。今日內容是和大家分享VBA編程中常用的 「積木」過程代碼,這些內容大多是取至我編寫的「VBA代碼解決方案」教程中內容。