最近更新

借助Graalvm設計自己的開發語言

SimpleLanguage 簡介

我們發現,開始實作您自己的語言的最簡單方法是擴充現有語言,例如 SimpleLanguage。 SimpleLanguage是一種使用Language API建構的示範語言。SimpleLanguage 項目展示了如何使用語言 API 編寫您自己的語言。它旨在使用大多數可用的Truffle 語言實作架構(以下簡稱“Truffle”)功能,并通過内聯源文檔廣泛記錄它們的使用。

首先,確定Maven3和 GraalVM 在您的系統中可用。

使用以下指令克隆 SimpleLanguage 存儲庫:

git clone https://github.com/graalvm/simplelanguage
           

JAVA_HOME使用 Linux 的指令行 shell 将環境變量和環境變量設定PATH為 GraalVM 主目錄和 bin 檔案夾:

export JAVA_HOME=/path/to/graalvmexport PATH=/path/to/graalvm/bin:$PATH           

對于 macOS,請使用:

export JAVA_HOME=/path/to/graalvm/Contents/Homeexport PATH=/path/to/graalvm/Contents/Home/bin:$PATH           

原文部落格 wuxiongwei.com

mvn package從 SimpleLanguage 檔案夾執行以建構語言。該指令還在目錄中建構一個slnative可執行檔案simplelanguage/native和一個sl-component.jar語言元件,稍後可以使用GraalVM Updater工具将其安裝到 GraalVM 中。請驗證該native-image插件在您的 GraalVM 發行版中是否可用,以避免建構失敗:

gu list gu install native-image

您可以通過運作以下指令在打包階段禁用 SimpleLanguage 本機可執行檔案建構:

export SL_BUILD_NATIVE=falsemvn package           

在 SimpleLanguage 根檔案夾中運作:

./sl ./language/tests/HelloWorld.sl
           

SimpleLanguage 示範語言根據通用許可許可證(UPL) 獲得許可。

IDE 設定

Truffle 架構提供了與語言無關的基礎設施,通過提供額外的 API 來實作标準 IDE 功能。如果您想試驗您的語言并獲得 IDE 的好處,請考慮導入 SimpleLanguage 作為示例。

原文部落格 wuxiongwei.com

Eclipse

SimpleLanguage 教學項目已經使用 Eclipse Neon.2 Release 4.6.2 和 Eclipse Oxygen.3A 進行了測試。要将項目檔案夾導入所需的 Eclipse 環境:

  1. 使用新工作區打開 Eclipse。
  2. 從 Eclipse 市場(Help -> Eclipse Marketplace)安裝m2e和插件。m2e-apt
  3. 最後,SimpleLanguage從 File -> Import -> Maven -> Existing Maven Projects -> 浏覽到 SimpleLanguage 檔案夾 -> Finish 導入項目。

NetBeans

NetBeans 為調試任意語言提供 GUI 支援。要将 SimpleLanguage 上傳到 NetBeans 界面,請執行檔案 -> 打開項目 -> 選擇simplelanguage檔案夾 -> 選中打開所需項目 -> 打開項目。

IntelliJ IDEA

SimpleLanguage 項目已使用 IntelliJ IDEA 進行了測試。打開 IntelliJ IDEA,然後從主菜單欄中選擇 File -> Open -> Navigate to 并選擇simplelanguage檔案夾 -> 按 OK。所有依賴項都将自動包含在内。

運作 SimpleLanguage

要運作 SimpleLanguage 源檔案,請執行:

原文部落格 wuxiongwei.com

./sl language/tests/HelloWorld.sl
           

要檢視已編譯函數的彙編代碼,請運作:

./sl -disassemble language/tests/SumPrint.sl
           

轉儲圖

要調查性能問題,我們推薦使用Ideal Graph Visualizer (IGV) ,它是建構在Oracle GraalVM 企業版之上的任何語言實施者的必備工具。它可以在Oracle 技術網下載下傳頁面上單獨下載下傳。

解壓下載下傳的包,進入bin目錄,啟動IGV:

cd idealgraphvisualizer/binidealgraphvisualizer           

從 SimpleLanguage 根檔案夾執行以下指令将圖形轉儲到 IGV:

./sl -dump language/tests/SumPrint.sl
           

調試

要使用 Java 調試器開始調試 SimpleLanguage 實作,請将-debug選項傳遞給程式的指令行啟動器:

./sl -debug language/tests/HelloWorld.sl
           

然後在端口 8000 上附加一個 Java 遠端調試器(如 Eclipse)。

GraalVM 的 SimpleLanguage 元件

使用Truffle 架構實作的語言可以打包為元件,以後可以使用GraalVM Updater工具将其安裝到 GraalVM 中。mvn package在 SimpleLanguage 檔案夾中運作也會建構一個sl-component.jar. 該檔案是 GraalVM 的 SimpleLanguage 元件,可以通過運作以下指令進行安裝:

gu -L install /path/to/sl-component.jar
           

SimpleLanguage 原生圖像

使用 Truffle 建構的語言可以使用Native Image進行 AOT 編譯。mvn package在 SimpleLanguage 檔案夾中運作還會slnative在該目錄中建構一個可執行檔案native。該可執行檔案是作為單個原生應用程式的完整 SimpleLanguage 實作,不需要 GraalVM 即可執行 SimpleLanguage 代碼。除此之外,與在 GraalVM 上運作相比,使用本機可執行檔案的一大優勢是啟動時間大大加快,如下所示:

原文部落格 wuxiongwei.com

time ./sl language/tests/HelloWorld.sl== running on org.graalvm.polyglot.Engine@2db0f6b2Hello World! real    0m0.405suser    0m0.660ssys     0m0.108s time ./native/slnativelanguage/tests/HelloWorld.sl== running on org.graalvm.polyglot.Engine@7fd046f06898Hello World! real    0m0.004suser    0m0.000ssys     0m0.000s           

該片段顯示了使用啟動器腳本定時執行“Hello World”程式,該sl啟動器腳本使用 Native Image 在 GraalVM 上運作 SimpleLanguage。我們可以看到,在 GraalVM 上運作時,執行需要 405 毫秒。由于我們的 SimpleLanguage 程式隻執行一條列印語句,我們可以得出結論,幾乎所有這些時間都花在了啟動 GraalVM 和初始化語言本身上。當使用本機可執行檔案時,我們看到執行隻需要 4 毫秒,這表明啟動速度比在 GraalVM 上運作快兩個數量級。

有關該native-image工具的更多資訊,請考慮閱讀參考手冊。

禁用 SimpleLanguage Native Image Build

通過 Maven 建構本機可執行檔案附加到 Mavenpackage階段。SL_BUILD_NATIVE由于本機可執行檔案建構可能需要一些時間,我們通過将環境變量設定為如下方式提供跳過此建構的選項false:

export SL_BUILD_NATIVE=falsemvn package...[INFO][INFO] ------------------------------------------------------------------------[INFO] Building simplelanguage-graalvm-native[INFO] ------------------------------------------------------------------------[INFO][INFO] --- exec-maven-plugin:1.6.0:exec (make_native) @ simplelanguage-graalvm-native ---Skipping the native image build because SL_BUILD_NATIVE is set to false.[INFO] ------------------------------------------------------------------------[INFO] BUILD SUCCESS[INFO] ------------------------------------------------------------------------...           

使用最新(開發)版本的編譯器運作 SimpleLanguage

要使用 Graal 編譯器的開發版本運作 SimpleLanguage,我們必須使用該編譯器建構 GraalVM。克隆graal存儲庫 (https://github.com/oracle/graal) 并按照vm/README.md檔案中的說明建構 GraalVM。

完成後,指向JAVA_HOME建立的 GraalVM 并繼續正常建構和運作 SimpleLanguage。

使用指令行運作 SimpleLanguage

執行 SimpleLanguage 代碼通常使用腳本來完成,該sl腳本設定必要的指令行,具體取決于JAVA_HOME指向 GraalVM 還是其他 JVM 安裝。以下小節描述了這兩種情況的指令行。

使用 GraalVM 作為 JAVA_HOME 運作 SimpleLanguage

假設JAVA_HOME指向 GraalVM 安裝并且目前工作目錄是該simplelanguage目錄,要運作 SimpleLanguage 應該執行以下指令:

$JAVA_HOME/bin/java \    -cp launcher/target/launcher-22.1.0-SNAPSHOT.jar \    -Dtruffle.class.path.append=language/target/simplelanguage.jar \    com.oracle.truffle.sl.launcher.SLMain language/tests/Add.sl           

簡而言之,我們将啟動器 JAR 放在類路徑上并執行其主類,但我們通過使用-Dtruffle.class.path.append選項通知 GraalVM SimpleLanguage 的存在并向其提供胖語言 JAR 的路徑。将語言放在單獨的類路徑上可確定語言實作與其嵌入上下文(在本例中為啟動器)之間的強分離。

禁用類路徑分離

筆記!這應該隻在開發過程中使用。

出于開發目的,禁用類路徑分離并在應用程式類路徑上啟用語言實作(例如,用于測試語言的内部)很有用。

Maven Central 上的 Language API JAR 導出其子產品資訊中的所有 API 包。–upgrade-module-path将此選項與此 JAR 一起應用-Dgraalvm.locatorDisabled=true以導出語言 API 包:

-Dgraalvm.locatorDisabled=true --module-path=<yourModulePath>:${truffle.dir} --upgrade-module-path=${truffle.dir}/truffle-api.jar
           

用于導出語言 API 包的示例 POM–upgrade-module-path可以在Simple Language POM.xml檔案中找到。

注意:禁用定位器會有效地從子產品路徑中删除所有已安裝的語言,因為定位器還會為這些語言建立類加載器。要繼續使用内置語言,請将子產品路徑指向所有需要的語言主目錄(例如,$GRAALVM/languages/js),将它們添加到子產品路徑中。

其他 JVM 實作

與包含運作使用Truffle實作的語言所需的所有依賴項的 GraalVM 不同,其他 JVM 實作需要額外的 JAR 才能出現在類路徑上。這些是 Maven Central 提供的 Language API 和 GraalVM SDK JAR。

假設JAVA_HOME指向一個股票 JDK 安裝,并且目前工作目錄是該simplelanguage目錄,并且該目錄中存在 Language API 和 GraalVM SDK JAR,可以使用以下指令執行 SimpleLanguage:

$JAVA_HOME/bin/java \    -cp graal-sdk-22.1.0.jar:truffle-api-22.1.0.jar:launcher/target/launcher-22.1.0-SNAPSHOT.jar:language/target/simplelanguage.jar \    com.oracle.truffle.sl.launcher.SLMain language/tests/Add.sl           

原文部落格 wuxiongwei.com

Activity基本概念

目錄

1.android:alwaysRetainTaskState

2.android:clearTaskOnLaunch

3.android:configChanges

4.android:excludeFromRecents

5.android:finishOnTaskLaunch

6.android:launchMode(Activity加載模式)

7.android:multiprocess

8.android:noHistory

9.android:screenOrientation

10.android:stateNotNeeded

11.android:windowSoftInputMode

Activity通常是應用程式中的單個螢幕,每個Activity都是作為擴充Activity基類的單個類來實作的。移動轉換到另外一個螢幕界面是通過開始一個新的Activity來實作的。在某些情況下,一個Actiivit可能會傳回一個值回到前一個Activity界面。當一個新的螢幕打開時,前一個螢幕會暫停并推送到曆史堆棧裡。Android系統保留了從主螢幕啟動的每一個應用程式的曆史堆棧,是以使用者可以通過曆史打開的螢幕向後導航。如果不需要保留,也可以選擇從曆史堆棧中删除界面。

接下來介紹Activity的屬性。

1.android:alwaysRetainTaskState

是否儲存狀态不變。例如:切換Home,在重新打開,則Activity處于最後的狀态。當一個浏覽器擁有很多狀态(當打開多個TAB),使用者并不希望丢失這些狀态時,可将此設定為true。

2.android:clearTaskOnLaunch

用來表明當再次啟動Task時,系統是否會清除了跟Activity以外的所有Activity,預設值是false.

3.android:configChanges

可以在manifest.xml檔案中指定Android參數configChanges,用于捕獲手機狀态的改變,如螢幕方向(orientation)的變化。在Activity中添加了android:configChanges屬性後,當所指定的屬性發生改變時,會通知程式調用onConfigurationChanged()函數。設定方法是将字段用“|”符号分隔開,如“locale|navigation|orientation”.在Android預設情況下,當oritaiton變化時會銷毀Activity,然後建立新的Activity。如果不希望重新建立Activity,可以在AndroidManifest..xml中配置Activity:<activity android:name=".MainActivity" android:configChanges="|orirntation">,這樣就不會在oritaiton變化時銷毀重建Activity,而是調用Activity的onConfigurationChanges()方法。

4.android:excludeFromRecents

是否可被顯示在最近打開的Activity清單裡。預設值是false.

5.android:finishOnTaskLaunch

當使用者重新啟動這個任務時,是否關閉已打開的Activity。預設值是false。

這個屬性與上面的clearTaskOnLaunch很像,不過它是指單個Activity,而不是整個棧。當設定為true時,Task重新開機後,這個 Activity就不顯示了。預設值是false。

6.android:launchMode(Activity加載模式)

在多Activity開發中,有可能是自己應用之間的Activity跳轉,或者夾帶其他應用的可複用Activity。如果希望跳轉到原來某個Activity執行個體,而不是産生大量重複的Activity。這就需要為Activity配置特定加載模式,而不是使用預設的加載模式。

Activity有中加載模式:standard、singleTop、singleTask、singleInstance(其中前兩個是一組、後兩個是一組)。預設為standard。

standard:這是個預設模式,可以不用寫配置。在這個模式下,都會預設建立一個新的執行個體。是以,在這種模式下,每次跳轉都會生成新的Activity,次模式下可以有多個相同的執行個體,也允許多個相同的Activity疊加。

singleTop:也是發送新的執行個體,但singleTop不同于standard的一點是,當請求的Activity正好位于棧頂時(配置成singleTop的Activity),不會構造新的執行個體。

singleTask:和後面的singleInstance為一組,都隻會建立一個執行個體。當Intent到來,需要建立設定為singleTask的Activity時,系統會檢查棧中是否已經有該Activity的執行個體,如果有則直接将Intent發送給它。

singleInstance:首先說明一下Task這個概念,Task可以被認為是一個棧,可存放多個Activity。例如,如果要啟動一個應用,Android會建立一個Task,随後這個應用的入口即被啟動,如果調用其他Activity也在同一個Task裡面。如果在多個Task中共享一個Activity該如何處理呢?舉個例子,如果開啟一個導航服務類的應用程式,裡面有一個Activity是開啟Google地圖的,當按下Home鍵退出回到主菜單又啟動Google地圖的應用時,顯示的就是剛才的地圖,這實際上是因為他們是同一個Activity,即引入了singleInstance。singleInstance模式下就是将Activity單獨放在一個棧中,這個棧中隻有這一個Activity,不同應用的Intent都這個Activity接收和展示,這樣就做到了共享。當然前提是這些應用都沒有被銷毀,按下Home鍵即儲存了這些應用,如果按下傳回鍵,則無效。

7.android:multiprocess

是否允許許多程序。預設值為false。

8.android:noHistory

當使用者從Activity上離開并且它在螢幕上不再可見時,Activity是否從Activity stack中清除并結束。預設值是false,Activity不會留下曆史痕迹。

9.android:screenOrientation

Activity顯示的模式。預設值是unspecified。系統自動判斷顯示方向,landscape為橫屏模式,寬度比高度大;portrait為豎屏模式,高度比寬度大。user模式:使用者目前首選的方向。beind模式:和該Activity下面的那個Activity大方向一緻(在Activity堆棧中)。ensor模式:由實體的感應器來決定,如果使用者旋轉裝置則螢幕會橫豎屏切換。nosensor模式:忽略實體感應器,這樣就不會随者使用者旋轉裝置而更改了。

10.android:stateNotNeeded

Activity被銷毀或成功重新開機時是否儲存狀态。

11.android:windowSoftInputMode

Activity主視窗與軟鍵盤的互動模式,可以用來避免輸入法面闆遮擋問題。

通常情況下,Activity有三種狀态:當螢幕前台時,響應使用者操作的Activity,處于激活或運作狀态;當它上面有另外一個Activity,使它失去焦點但仍然對使用者可見時,處于暫停狀态;當它完全被另外一個Activity覆寫則處于停止狀态。Activity從一種狀态轉變到另一種狀态時,會調用其生命周期方法。Activity一共7中生命周期方法具體如下表1-1所示。

表1-1 Activity生命周期

方法名 說明
void onCreate() 設定布局及進行初始化操作
void onStart() 可見,但不可互動
void onRestart() 調用onStart()
void onResume() 可見,可互動
void onPause() 部分可見,不可互動
void onStop() 完全不可見
void onDestory() 銷魂

startActivity開啟一個Activity時,生命周期執行的方法是:onCreate()->onStart()->onResume()

單擊Back鍵關閉Activity時,生命周期執行的方法是:onPause()->onStop()->onDestory()

當開啟一個新的Activity(以對話框形式),新的Activity把後面的Activity蓋住一部分時,後面的Activity的生命周期執行的方法是:onPause()注意,指定Activity一對話框的形式顯示,需要在Activity節點追加以下主題Android:theme="@android:style/Theme.Dialog"。

當把新開啟的Activity(以對話框形式)關閉時,後面的Activity的生命周期執行方法是:onResume()。

當把新開啟的Activity,把後面的Activity完全蓋住時,生命周期執行的方法是:onPause()->onStop()。

當把新開啟的Activity(完全蓋住)關閉時,生命周期的執行方法是:onRestart()->onStart()-onResume()