46
34

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

ソフト技研Advent Calendar 2018

Day 7

各言語環境を Linux (WSL) に asdf で構築

Last updated at Posted at 2018-12-06

サーバ上でアプリケーションを動作させたり、バイナリをビルドするために、特定のバージョンのプログラム言語プラットフォームを必要とすることがある。
あらかじめ Docker で動くように設計されているのであれば Docker で十分だが、全てが対応しているわけではない。

そんな時良く使われるのが、***env 系のバージョン管理ツール。

env 系ツール

元々は rbenv が始まりらしいが、今では様々な言語向けに移植されている。
できることは大体同じで、

  • 特定のバーションを取得 (ビルド)
  • グローバルに利用するバージョンの管理
  • フォルダ毎にバージョンを固定
    • ローカルに何かしらの dotfile を置き、そこに設定する
    • 環境変数で切り替える
  • shims の管理

ただ、言語ごとに **env をいちいち取ってきてシェルの設定するのが面倒なので、その場合は **env を管理する anyenv がよく使われる。

とはいえ、**env 系はメンテナンスが止まっているものもあったりと、不満もあった。
そこで、自分は asdf というツールに乗り換えた。

asdf

asdf は、様々なプログラム言語やツールの実行環境・SDK のバージョン管理を行う為のツール。
https://github.com/asdf-vm/asdf

管理できる対象は以下で一覧できる。
https://github.com/asdf-vm/asdf-plugins#plugin-list

一覧を見れば分かるが、プログラム言語の管理だけを目的としているわけではない。
kubectl や bazel などの CLI ツールや、Elasticsearch や MongoDB などのミドルウェアも何故か扱える。
が、今回はプログラム言語プラットフォームだけを対象とする。

対象言語

自分が知っている言語を抜き出してみた。

Language Repository
Clojure halcyon/asdf-clojure
Coq gingerhot/asdf-coq
Crystal marciogm/asdf-crystal
D (DMD) sylph01/asdf-dmd
Elixir asdf-vm/asdf-elixir
Elm vic/asdf-elm
Erlang asdf-vm/asdf-erlang
Go kennyp/asdf-golang
GraalVM vic/asdf-graalvm
Haskell vic/asdf-haskell
Idris vic/asdf-idris
Java skotchpine/asdf-java
Julia rkyleg/asdf-julia
Kotlin missingcharacter/asdf-kotlin
Logtalk LogtalkDotOrg/asdf-logtalk
Lua Stratus3D/asdf-lua
LuaJIT smashedtoatoms/asdf-luaJIT
Nim rfrancis/asdf-nim
Node.js asdf-vm/asdf-nodejs
OCaml vic/asdf-ocaml
PHP odarriba/asdf-php
Python danhper/asdf-python
R iroddis/asdf-R
Racket vic/asdf-racket
Ruby asdf-vm/asdf-ruby
Rust code-lever/asdf-rust
Scala mtatheonly/asdf-scala
.Net Core emersonsoares/asdf-dotnet-core

2018/12 現在、メンテナンスもアクティブになされており、新しい言語にも対応していきそうだ。
新し目で言うと、GraalVM なんかもある。

インストール

手順は簡単

$ git clone https://github.com/asdf-vm/asdf.git ~/.asdf

# ついでに、プラグインでよく使われるパッケージをインストールしておく
$ sudo apt-get install -y automake autoconf libreadline-dev libncurses-dev libssl-dev libyaml-dev libxslt-dev libffi-dev libtool unixodbc-dev

あとは、お使いの Shell に設定追加するだけ。私は fisher です。

$ echo 'source ~/.asdf/asdf.fish' >> ~/.config/fish/config.fish
$ mkdir -p ~/.config/fish/completions; and cp ~/.asdf/completions/asdf.fish ~/.config/fish/completions

$ source ~/.asdf/asdf.fish

これで終わり。

$ asdf --version
# v0.6.2

使ってみる

Node.js

まずは、分かりやすく Node.js で挑戦。

$ asdf plugin-add nodejs
# 既に入っているなら、アップデート
$ asdf plugin-update nodejs

# バージョンリストを取得
$ asdf list-all nodejs
# 0.10.0
# 0.10.1
# ....

# インストール
$ asdf install nodejs 10.10.0
$ asdf install nodejs 11.3.0

# 不要ならアンインストール
$ asdf uninstall nodejs 9.11.0

グローバルに選択してみる

$ asdf global nodejs 11.3.0
$ node -v
# v11.3.0

# 現在のグローバルなバージョン
$ asdf current  nodejs
# 11.3.0   (set by /home/username/.tool-versions)

# インストールされたリストを一覧
$ asdf list nodejs
# 10.10.0
# 11.3.0

今度はプロジェクト毎に選択してみる

$ cd ./some_project_folder
$ asdf local nodejs 10.10.0
$ node -v
# v10.10.0

# ローカル設定は .tool-versions に保存
$ cat .tool-versions
# nodejs 10.10.0

# ディレクトリを抜ければ、もとに戻る
$ cd ..
$ node -v
# v11.3.0

ちなみに、shims はどうなってるかと言うと、

$ which node
# /home/username/.asdf/shims/node

$ cat /home/username/.asdf/shims/node
# #!/usr/bin/env bash
# # asdf-plugin: nodejs
# # asdf-plugin-version: 11.3.0
# # asdf-plugin-version: 10.10.0
# exec /home/username/.asdf/bin/private/asdf-exec nodejs bin/node "$@"

# 元のフォルダの位置
$ asdf where nodejs
# /home/username/.asdf/installs/nodejs/11.3.0

# 貼り直し
$ asdf reshim nodejs

これだけできれば十分。

Go

次は、Go でやってみる。

$ asdf plugin-add golang

# バージョンリストを取得
$ asdf list-all golang
# 1.2.2
# 1.3
# ....

# インストール
$ asdf install golang 1.11.2

$ asdf global nodejs 1.11.2
$ go version
# go version go1.11.2 linux/amd64

$ go env
# GOARCH="amd64"
# GOBIN=""
# GOCACHE="/home/username/.cache/go-build"
# GOEXE=""
# GOFLAGS=""
# GOHOSTARCH="amd64"
# GOHOSTOS="linux"
# GOOS="linux"
# GOPATH="/home/username/.asdf/installs/golang/1.11.2/packages"
# GOPROXY=""
# GORACE=""
# GOROOT="/home/username/.asdf/installs/golang/1.11.2/go"
# GOTMPDIR=""
# GOTOOLDIR="/home/username/.asdf/installs/golang/1.11.2/go/pkg/tool/linux_amd64"
# GCCGO="gccgo"
# CC="gcc"
# CXX="g++"
# CGO_ENABLED="1"
# GOMOD=""
# CGO_CFLAGS="-g -O2"
# CGO_CPPFLAGS=""
# CGO_CXXFLAGS="-g -O2"
# CGO_FFLAGS="-g -O2"
# CGO_LDFLAGS="-g -O2"
# PKG_CONFIG="pkg-config"
# GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build209186154=/tmp/go-build -gno-record-gcc-switches"# 

GOROOTGOPATH が存在しない場合、shims の中の asdf-exec 実行時に、$ASDF_INSTALL_PATH/go$ASDF_INSTALL_PATH/packages に設定される。
https://github.com/kennyp/asdf-golang/blob/master/bin/exec-env

実際にやってみると、$ASDF_INSTALL_PATH/home/username/.asdf/installs/golang/1.11.2/ になった。
普通に set -x GOPATH $HOME/go と設定すればそっちが優先される。

Python

Python は、内部では pyenv を利用し、asdf のインターフェイスに合わせただけのようだ

Java (JDK)

Java は、list-all で表示するバージョンが 固定となっており、選べる OpenJDK は、openjdk-10.0.2 openjdk-11 openjdk-11.0.1 だけとなっている。

まぁ、サポート期間を考えて 10 未満を切り捨てているのであれば仕方ないのかも知れないが。

ちなみに、OracleJDK ではまだ 8 が存在している。

Rust や Haskell はどうすべきか問題

例えば、Rust には rustup があり、Haskell には stack がある。

これらは、

  • 公式 or デファクトスタンダードなプラットフォームバージョン管理ツール
  • ツールは安定し、使いやすく、メンテナンスもアクティブに続いている
  • ネット上の技術情報がそのツール利用を前提とするものが多い
  • バージョン管理以外にも、重要な役割が存在する

という状況で、無理をして asdf のような外部のツールで管理する必要はあるか。

ということで、Rust と Haskell は大人しく rustup と stack を使っている。

サードパーティ製プラグイン

好きな言語が対応していない場合には、自分でプラグインを書いて追加もできる。

$ asdf plugin-add <name> <git-url>

最低限、list-allinstall があれば動くので、サクッと作れる。

感想

使っていて、手に馴染む感覚はある。
バージョン情報のコンプリーションもしっかりしてくれるし、対応言語も多い。
そういえば、scoop に使い心地も似ているのもあるかも。

あとがき

※ この記事は個人の見解であり、所属する組織を代表するものではありません。

46
34
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
46
34

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?