1. 程式人生 > >編譯V8引擎

編譯V8引擎

由於專案專案中最近用到v8引擎,專案由sparkmonkey切換到v8後,效能有了較大的提升,不過美中不足的是,啟動時間較長,檢視v8相關的文件,可以使用snapshot快照技術加快啟動速度,因此覺得自己編譯v8,加速啟動。

在編譯過程中遇到各種問題,首先說編譯環境,專案需求是在android中使用v8快照,一般生成android平臺的v8連結庫有三種形式,在windows環境編譯,在windows環境下使用cgwin編譯,在linux環境下編譯。

  • 使用window環境編譯

    v8最新版本會強制繫結到vs2017,就算指定僅編譯android平臺也不能拿避免,沒有裝vs2017,目前專案使用vs2015,升級設計比較多的人,故舍棄此方案。(可能有其他引數避免這種繫結,不瞭解暫時沒有深究)

  • 使用window環境下cgwin編譯

    在cgwin環境下前期正常,但在相關指令碼的呼叫中,遇到一個路徑中斜槓”\”和反斜槓”/”的報錯,由於關聯指令碼是從遠端庫自動下載,無法本地修改,如果要一一修改,需要將指令碼加入到本地索引中,因此也沒有使用這種方案。

  • 使用linux環境編譯

    使用linux環境編譯目前遇到問題最少,基本都是自動指令碼執行完成,linux中還缺少部分系統庫,手動新增一下就好。

開始編譯v8,分為三個部分,第一個準備環境,linux使用虛擬機器wmware,裝centos最新穩定版本,注意硬碟要分配30G以上,因為要下載ndk以及一大堆第三方程式碼,建議留足編譯空間。

  • 前期準備

    裝完centos後,先需要安裝gcc gcc-c++

    yum install -y gcc
    yum install -y gcc-c++

    安裝depot_tools,主要用來下載指令碼,有兩個工具 fetch,gclient

    git clone https://chromium.googlesource.com/chromium/tools/depot_tools
    

    修改系統環境變數,將depot_tools加入到系統命令當中

    vim /etc/profile
    ...
    export PATH=/*(目錄)/depot_tools:$PATH

    編譯可以使用fetch v8來預設編譯,這條命令相當於先建立一個預設的.gclient配置描述檔案,然後再指向gclient sync下載相關依賴專案,我們可以採用自己建立.gclient檔案定製下載選項

    gclient config https://github.com/v8/v8.git

    這個時候,在當前工作目錄下會生成一個.gclient檔案,使用編輯器開啟它

    solutions = [
      { "name"        : "v8",
        "url"         : "https://github.com/v8/v8.git",
        "deps_file"   : "DEPS",
        "managed"     : True,
        "custom_deps" : {
        },
      },
    ]
    cache_dir = None
    target_os = ["android"]
    target_os_only = True
    target_cpu = "arm"
    is_component_build = True
    

根據需要自己定製編譯目標,修改完成後,再執行

  • 執行命令

    gclient sync
  • 編譯指定版本

    這之後gclient會自動下載v8原始碼,以及相關依賴專案。如果要指定某個v8版本編譯,則需要先下載這個v8工程,再切換到對應版本,然後檢出一個本地分支

    git clone https://github.com/v8/v8.git
    git checkout 6.0.328
    git checkout -b myv8
    gclient sync --with_branch_heads --jobs=1

    會遇到是否下載合併程式碼,選skip跳過,就可以在當前分支版本繼續執行編譯命令

  • 錯誤處理

    在編譯過程中可能會遇到指令碼報錯,基本上是系統的某些庫檔案找不到,例如:

    ninja: Entering directory `out/foo/'
    [1252/1707] ACTION //:run_mksnapshot(//build/toolchain/android:android_arm)
    FAILED: gen/snapshot.cc snapshot_blob.bin 
    python ../../tools/run.py ./clang_x86_v8_arm/mksnapshot --startup_src gen/snapshot.cc --random-seed 314159265 --startup_blob snapshot_blob.bin
    ./clang_x86_v8_arm/mksnapshot: error while loading shared libraries: libstdc++.so.6: cannot open shared object file: No such file or directory
    [1253/1707] CXX obj/v8_base/code-stub-assembler.o
    ninja: build stopped: subcommand failed.

    找到出錯指令碼單獨執行就可以看到報錯

    python ../../tools/run.py ./clang_x86_v8_arm/mksnapshot --startup_src gen/snapshot.cc --random-seed 314159265 --startup_blob snapshot_blob.bin
    ./clang_x86_v8_arm/mksnapshot: error while loading shared libraries: libstdc++.so.6: cannot open shared object file: No such file or directory

    定位到問題,系統缺少libstdc++.so.6,使用yum命令安裝對應庫即可

  • 編譯靜態庫
    由上述步驟,已經下載好整套編譯環境,預設會下載到當前目錄下的v8目錄,切換隻目錄到v8資料夾,進入編譯流程,先配置編譯引數,使用gn命令生成編譯引數

    gn args out/foo

    這時會開啟一個名為args.gn的文字檔案,根據需要填入以下引數

    
    # Build arguments go here.
    
    
    # See "gn args <out_dir> --list" for available build arguments.
    
    target_cpu = "arm"
    target_os = "android"
    v8_target_cpu = "arm"
    v8_static_library = true
    v8_enable_i18n_support = false
    v8_use_snapshot = true
    is_component_build = false

    敲入一下命令啟動編譯過程,執行完成就可以獲得相應的靜態庫

    gn gen out/foo
    ninja -C out/foo

    最後遇到一個找不到libplatform.a的問題,看了網上的大多數解決方案,都不是很靠譜,自行研究發現其實挺簡單,修復ninja編譯命令引數檔案,將libplatform.stamp檔案編譯為libplatform.a檔案

    在執行完 gn gen out/foo 後先修改out/foo/build.ninja檔案中v8_libplatform.stamp 改為 v8_libplatform.a,一共有三個地方

    build v8_libbase: phony obj/v8_libbase.stamp
    build v8_libplatform: phony obj/v8_libplatform.stamp ##  => v8_libplatform.a
    build v8_libsampler: phony obj/libv8_libsampler.a
    build v8_maybe_snapshot: phony obj/v8_maybe_snapshot.stamp
    build v8_nosnapshot: phony obj/libv8_nosnapshot.a

    再修改out/foo/obj/build.ninja,參照其他.a檔案的生成規則,將最後一行改為生成.a檔案

    build obj/v8_libplatform.stamp: stamp obj/v8_libplatform/default-platform.o obj/v8_libplatform/task-queue.o obj/v8_libplatform/trace-buffer.o obj/v8_libplatform/trace-config.o obj/v8_libplatform/trace-object.o obj/v8_libplatform/trace-writer.o obj/v8_libplatform/tracing-controller.o obj/v8_libplatform/worker-thread.o || obj/v8_libbase.stamp obj/build/config/exe_and_shlib_deps.stamp
    
    ##=>
    
    build obj/libv8_libplatform.a: alink obj/v8_libplatform/default-platform.o obj/v8_libplatform/task-queue.o obj/v8_libplatform/trace-buffer.o obj/v8_libplatform/trace-config.o obj/v8_libplatform/trace-object.o obj/v8_libplatform/trace-writer.o obj/v8_libplatform/tracing-controller.o obj/v8_libplatform/worker-thread.o || obj/v8_libbase.stamp obj/build/config/exe_and_shlib_deps.stamp
     arflags =
     output_extension = .a
     output_dir = obj

    最後執行 ninja -C out/foo編譯專案,生成靜態庫

總結一下就是,專案中引入的依賴太多,才導致編譯變得比較複雜,而且很多都是google的指令碼,找不到命令文件,所以執行起來比較容易出問題。

參考文件: