JavaScript/TypeScript ランタイムの Deno を OpenIndiana に移植しました。
なぜ Deno?
Deno は Node.js の作者である Ryan Dahl によって作成された JavaScript/TypeScript ランタイムです。詳細は上記 Wikipedia を参照してください。
最近の Vim 界隈では Deno を利用したプラグインエコシステム Denops が流行っており、OpenIndiana でも使ってみたいと思ったものの、Deno の対応 OS は Windows, macOS, Linux だけです。
そこで、OpenIndiana に移植することにしました。
ビルド環境の準備
Deno のビルドに必要なソフトウェアをインストールします。
Deno は Rust で書かれているため、Rust のツールチェインが必要です。Rustup を使ってツールチェインをインストールします。
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh # ~/.cargo/bin にパスを通しておく rustup update
OpenIndiana のパッケージシステム pkg でビルドに必要なパッケージをインストールします。
sudo pkg install gcc-7 clang-13 ninja
gcc-7 の依存パッケージ g++-7-runtime により libstdc++ がインストールされ、g++ および clang++ は C++ プログラム生成時にこれをリンクします。
しかし、この libstdc++ はデフォルトの 64bit ライブラリパス /lib/amd64:/usr/lib/amd64
ではなく /usr/gcc/7/lib/amd64
下に配置されるため、そのままではリンク時に失敗します。
今回は、crle でライブラリパスを追加することで対処します。
sudo crle -64 -u -l /usr/gcc/7/lib/amd64
その他、メタビルドシステム gn が必要ですが、これはソースからビルドする必要があります。
# リポジトリを取得 git clone https://gn.googlesource.com/gn cd gn # ninja のビルドファイルを生成 # clang はデフォルトでは 32bit バイナリを出力するため、"-m64" オプションを指定して 64bit バイナリにする (必須ではない) # ar は /usr/gnu/bin 下にある gnu ar ではフォーマットが合わない (Solaris の ar が必要) ため、PATH に /usr/gnu/bin が入っている場合はフルパスを指定する CXX='clang++ -m64' AR=/usr/bin/ar LD=/usr/bin/ld python build/gen.py # ビルド ninja -C out
パスの通っているディレクトリにインストールします。
# ~/.local/bin にパスを通しておく install -m755 out/gn ~/.local/bin
移植する
Deno のバージョンは執筆時点 (2022/5/9) での最新である 1.21.2 とします。
依存ライブラリのうち、illumos (OpenIndiana のカーネル) 対応していないものについては、ソースコードをローカルにダウンロードして変更を加えます。
errno
最新バージョンでは illumos に対応していますが、Deno はそれより古いバージョンを参照するため、Cargo.toml を変更してバージョンを詐称します。
git clone https://github.com/lambda-fairy/rust-errno cd rust-errno git checkout v0.2.8
--- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "errno" -version = "0.2.8" +version = "0.1.8" authors = ["Chris Wong <lambda.fairy@gmail.com>"] license = "MIT/Apache-2.0"
v8
JavaScript エンジン V8 の Rust バインディングを提供するライブラリです。
Solaris/illumos 用のビルド設定を追加することが主な内容になります。
git clone https://github.com/denoland/rusty_v8 cd rusty_v8 git checkout v0.42.0
--- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,2 +1,9 @@ [target.aarch64-linux-android] linker = "./third_party/android_ndk/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android21-clang++" + +[target.x86_64-unknown-illumos] +rustflags = ["-C", "link-args=-lffi -lstdc++"] + +[env] +V8_FROM_SOURCE = "1" +CLANG_BASE_PATH = "/usr" --- a/build/config/BUILDCONFIG.gn +++ b/build/config/BUILDCONFIG.gn @@ -211,6 +211,12 @@ if (host_toolchain == "") { } } else if (host_os == "aix") { host_toolchain = "//build/toolchain/aix:$host_cpu" + } else if (host_os == "solaris") { + if (is_clang) { + host_toolchain = "//build/toolchain/solaris:clang_$host_cpu" + } else { + host_toolchain = "//build/toolchain/solaris:$host_cpu" + } } else { assert(false, "Unsupported host_os: $host_os") } @@ -253,6 +259,12 @@ if (target_os == "android") { _default_toolchain = "//build/toolchain/win:uwp_$target_cpu" } else if (target_os == "aix") { _default_toolchain = "//build/toolchain/aix:$target_cpu" +} else if (target_os == "solaris") { + if (is_clang) { + _default_toolchain = "//build/toolchain/solaris:clang_$target_cpu" + } else { + _default_toolchain = "//build/toolchain/solaris:$target_cpu" + } } else { assert(false, "Unsupported target_os: $target_os") } @@ -291,6 +303,7 @@ is_linux = current_os == "linux" is_mac = current_os == "mac" is_nacl = current_os == "nacl" is_win = current_os == "win" || current_os == "winuwp" +is_solaris = current_os == "solaris" is_apple = is_ios || is_mac is_posix = !is_win && !is_fuchsia --- a/build/config/compiler/BUILD.gn +++ b/build/config/compiler/BUILD.gn @@ -399,7 +399,7 @@ config("compiler") { # compute, so only use it in the official build to avoid slowing down # links. ldflags += [ "-Wl,--build-id=sha1" ] - } else if (current_os != "aix") { + } else if (current_os != "aix" && current_os != "solaris") { ldflags += [ "-Wl,--build-id" ] } @@ -1244,7 +1244,7 @@ config("compiler_deterministic") { # Tells the compiler not to use absolute paths when passing the default # paths to the tools it invokes. We don't want this because we don't # really need it and it can mess up the goma cache entries. - if (is_clang && !is_nacl) { + if (is_clang && !is_nacl && !is_solaris) { cflags += [ "-no-canonical-prefixes" ] } } @@ -2046,7 +2046,7 @@ if (is_win) { "-Wl,-no_function_starts", ] } - } else if (current_os != "aix") { + } else if (current_os != "aix" && current_os != "solaris") { # Non-Mac Posix flags. # Aix does not support these. --- a/build/config/compiler/compiler.gni +++ b/build/config/compiler/compiler.gni @@ -197,7 +197,7 @@ declare_args() { # Not supported for macOS (see docs/mac_lld.md), and not functional at all for # iOS. But used for mac cross-compile on linux (may not work properly). # The default linker everywhere else. - use_lld = is_clang && (!is_apple || host_os == "linux") + use_lld = is_clang && ((!is_apple && !is_solaris) || host_os == "linux") } declare_args() { --- a/build/toolchain/gcc_toolchain.gni +++ b/build/toolchain/gcc_toolchain.gni @@ -376,6 +376,8 @@ template("gcc_toolchain") { # AIX does not support either -D (deterministic output) or response # files. command = "$ar -X64 {{arflags}} -r -c -s {{output}} {{inputs}}" + } else if (current_os == "solaris") { + command = "$ar {{arflags}} -r -c -s {{output}} {{inputs}}" } else { rspfile = "{{output}}.rsp" rspfile_content = "{{inputs}}" --- /dev/null +++ b/build/toolchain/solaris/BUILD.gn @@ -0,0 +1,46 @@ +# Copyright 2022 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//build/toolchain/gcc_toolchain.gni") + +gcc_toolchain("clang_x64") { + prefix = rebase_path("${clang_base_path}/bin", root_build_dir) + cc = "${prefix}/clang" + cxx = "${prefix}/clang++" + readelf = "readelf" + nm = "/usr/bin/nm" + ar = "/usr/bin/ar" + ld = cxx + + # Output linker map files for binary size analysis. + enable_linker_map = true + + toolchain_args = { + current_cpu = "x64" + current_os = "solaris" + + is_clang = true + } +} + +gcc_toolchain("x64") { + cc = "gcc" + cxx = "g++" + readelf = "readelf" + nm = "/usr/bin/nm" + ar = "/usr/bin/ar" + ld = cxx + + # Output linker map files for binary size analysis. + enable_linker_map = true + + toolchain_args = { + current_cpu = "x64" + current_os = "solaris" + + # reclient does not support gcc. + use_rbe = false + is_clang = false + } +} --- a/build.rs +++ b/build.rs @@ -251,6 +251,10 @@ fn platform() -> &'static str { { "mac" } + #[cfg(any(target_os = "solaris", target_os = "illumos"))] + { + "solaris" + } } fn download_ninja_gn_binaries() { --- a/v8/BUILD.gn +++ b/v8/BUILD.gn @@ -5148,7 +5148,7 @@ v8_component("v8_libbase") { "src/base/platform/platform-posix.cc", "src/base/platform/platform-posix.h", ] - if (current_os != "aix") { + if (current_os != "aix" && current_os != "solaris") { sources += [ "src/base/platform/platform-posix-time.cc", "src/base/platform/platform-posix-time.h", @@ -5173,6 +5173,17 @@ v8_component("v8_libbase") { ] libs = [ "dl" ] + } else if (current_os == "solaris") { + sources += [ + "src/base/debug/stack_trace_posix.cc", + "src/base/platform/platform-solaris.cc", + ] + + libs = [ + "dl", + "socket", + "rt", + ] } else if (is_android) { if (current_toolchain == host_toolchain) { libs = [
deno
Deno 本体のコードについては、 Solaris/illumos 対応のプルリクエストを出し、1.20.4 でマージされました。
Cargo.toml を編集し、ローカルのライブラリを参照するように変更します。
git clone https://github.com/denoland/deno cd deno git checkout v1.21.2
--- a/.cargo/config +++ b/.cargo/config @@ -12,3 +12,10 @@ rustflags = [ [target.aarch64-apple-darwin] rustflags = ["-C", "link-arg=-fuse-ld=lld"] + +[target.x86_64-unknown-illumos] +rustflags = ["-C", "link-args=-lffi -lstdc++"] + +[env] +V8_FROM_SOURCE = "1" +CLANG_BASE_PATH = "/usr" --- a/Cargo.toml +++ b/Cargo.toml @@ -174,3 +174,7 @@ opt-level = 3 opt-level = 3 [profile.release.package.zstd-sys] opt-level = 3 + +[replace] +"errno:0.1.8" = { path = "../rust-errno" } +"v8:0.42.0" = { path = "../rusty_v8" }
ビルドします。
cargo build --release -vv
V8 のビルド途中で clang がクラッシュすることがありますが、原因は深掘りしていません。
再度 cargo build
を実行すると成功するので、システムリソース関係かもしれません。
テストを通したいのですが、現状ではネットワーク関連の項目でハングします。今後の課題とします。
cargo test -vv
インストールします。ワンバイナリで構成されているため、取り回しがしやすいのも Deno の特長の一つです。
install -m755 target/release/deno ~/.cargo/bin
動作確認
TypeScript で簡単なサーバーを書いてみます。
main.ts
import { Server } from "https://deno.land/std@0.134.0/http/mod.ts"; const handler = function(_req: Request): Response { return new Response("Hello World!"); }; const port = 8000; const server = new Server({port, handler}); console.log("start server"); await server.listenAndServe();
deno run --allow-net main.ts
curl http://127.0.0.1:8000 # Hello World!
テストが通ってないので不安でしたが、これくらいなら問題なさそうです。
Denops プラグインを試す
Denops を利用するプラグインが動作するか確認します。
Vim 上で SKK 日本語入力を提供する skkeleton を試してみました。
少し動かしただけですが、特に問題なさそうでした。
まとめ
Deno を OpenIndiana に移植しました。これで OpenIndiana の Vim ユーザーでも Denops が利用できますね。
Gist にパッチを置いています。
参考リンク
移植については FreeBSD のパッチを参考にしました。