🐙
言語/ツールのコンパイルをしてみた。
- ruby
- C
- go
- python
- rust
- nginx
- node
実行環境
- dockerコンテナ
今回は、簡素なDockerfileを用いて学習。
使用するOSはubuntu。
目的
いつも私たちが何気なく使っているコンテナ。
私たちが使ってるイメージ、中身がどうなってるか知りたくない?という衝動で始めました。
ということで、さっそく下記のコンパイル用のイメージを作成。
各言語コンパイル
rubyコンパイル
FROM ubuntu:24.04
# Rubyメジャー・マイナーバージョン
ENV RUBY_SERIES=3.4
# Rubyバージョン
ENV RUBY_VERSION=3.4.3
# 必要なパッケージのインストール
RUN apt-get update && apt-get install -y \
git \
build-essential \
autoconf \
bison \
libssl-dev \
libreadline-dev \
zlib1g-dev \
libyaml-dev \
libffi-dev \
wget \
tar \
rustc \
&& rm -r /var/lib/apt/lists/*
# Rubyソースの取得ビルド
WORKDIR /usr/src
RUN wget https://cache.ruby-lang.org/pub/ruby/${RUBY_SERIES}/ruby-${RUBY_VERSION}.tar.gz && \
tar -xvzf ruby-${RUBY_VERSION}.tar.gz && \
cd ruby-${RUBY_VERSION} && \
./configure --prefix=/opt/ruby-${RUBY_VERSION} --enable-shared --disable-install-doc --enable-yjit && \
make -j$(nproc) && \
make install
# PATHを通す
ENV PATH="/opt/ruby-${RUBY_VERSION}/bin:$PATH"
# 確認
CMD ["ruby", "-v"]
Cコンパイル
FROM ubuntu:24.04
RUN apt-get update && apt-get install -y \
build-essential \
&& rm -rf /var/lib/apt/lists/*
CMD ["gcc", "--version"]
goコンパイル
FROM ubuntu:24.04
RUN apt-get update && apt-get install -y \
wget \
tar \
build-essential \
&& rm -rf /var/lib/apt/lists/*
ENV GO_VERSION=1.22.3
WORKDIR /usr/src
RUN wget https://go.dev/dl/go${GO_VERSION}.linux-amd64.tar.gz && \
tar -C /usr/local -xzf go${GO_VERSION}.linux-amd64.tar.gz && \
rm go${GO_VERSION}.linux-amd64.tar.gz
ENV PATH="/usr/local/go/bin:$PATH"
CMD ["go", "version"]
pythonコンパイル
FROM ubuntu:24.04
RUN apt-get update && apt-get install -y \
build-essential \
libssl-dev \
zlib1g-dev \
libncurses5-dev \
libsqlite3-dev \
libreadline-dev \
libffi-dev \
wget \
&& rm -rf /var/lib/apt/lists/*
# Pythonビルド
ENV PYTHON_VERSION=3.12.3
WORKDIR /usr/src
RUN wget https://www.python.org/ftp/python/${PYTHON_VERSION}/Python-${PYTHON_VERSION}.tgz && \
tar -xzf Python-${PYTHON_VERSION}.tgz && \
cd Python-${PYTHON_VERSION} && \
./configure --enable-optimizations && \
make -j$(nproc) && \
make altinstall
ENV PATH="usr/local/bin:$PATH"
CMD ["/usr/local/bin/python3.12", "--version"]
rustコンパイル
FROM ubuntu:24.04
RUN apt-get update && apt-get install -y \
curl \
ca-certificates \
&& rm -rf /var/lib/apt/lists/*
ENV RUST_VERSION=1.77.2
RUN curl -O https://static.rust-lang.org/dist/rust-${RUST_VERSION}-x86_64-unknown-linux-gnu.tar.gz && \
tar -xzf rust-${RUST_VERSION}-x86_64-unknown-linux-gnu.tar.gz && \
cd rust-${RUST_VERSION}-x86_64-unknown-linux-gnu && \
./install.sh --prefix=/usr/local
# パスを通す(通常 /usr/local/bin に入るが念のため)
ENV PATH="/usr/local/bin:$PATH"
CMD ["rustc", "--version"]
nginxコンパイル
FROM ubuntu:24.04
RUN apt-get update && apt-get install -y \
build-essential \
libpcre3-dev \
zlib1g-dev \
libssl-dev \
curl \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /usr/src
ENV NGINX_VERSION=1.26.0
RUN curl -O http://nginx.org/download/nginx-${NGINX_VERSION}.tar.gz && \
tar -xzf nginx-${NGINX_VERSION}.tar.gz && \
cd nginx-${NGINX_VERSION} && \
./configure --prefix=/usr/local/nginx \
--with-http_ssl_module && \
make -j$(nproc) && \
make install
ENV PATH="/usr/local/nginx/sbin:$PATH"
CMD ["nginx", "-v"]
nodeコンパイル
FROM ubuntu:24.04
ENV NODE_VERSION=v22.15.1
RUN apt-get update && apt-get install -y \
curl \
tar \
ca-certificates \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /usr/src
RUN curl -fsSLO https://nodejs.org/dist/${NODE_VERSION}/node-${NODE_VERSION}-linux-x64.tar.gz \
&& tar -xzf node-${NODE_VERSION}-linux-x64.tar.gz \
&& mv node-${NODE_VERSION}-linux-x64 /opt/nodejs \
&& ln -s /opt/nodejs/bin/node /usr/local/bin/node \
&& ln -s /opt/nodejs/bin/npm /usr/local/bin/npm
# 動作確認
CMD ["node", "--version"]
学んだこと
各言語の形式
言語 | 実行方式 | コンパイルツール | コンパイルタイミング |
---|---|---|---|
ruby | バイトコード解釈実行 | Ruby本体(MakefileはRuby自体のビルド用) | 実行時に自動コンパイル |
python | バイトコード解釈実行 | Python自体(バイトコード生成機能) | 実行時に自動コンパイル |
C | 事前に機械語へコンパイル | gcc等 | 実行前に明示的にコンパイル |
Go | 事前に機械語へコンパイル | Goツールチェーン内 | 実行前に明示的にコンパイル |
(rustはいいや。。。)
makeコマンドの一連の流れ
makeコマンドは言語のコードファイルをビルドするためのツール。
./configure
によって、makefileを作成。
make -j$(nproc)
によって、指定プロセッサによるmakefile実行。
installという命名だが、単にファイルをこぴっているだけ。(ややこし)
よくaptやrbenv, nvmで楽々インストール!している中ではこうなってたのか!という感情発見
地道に、curlやwgetで引っ張って、パイプでスクリプト実行したり、ファイルを解凍して地道にmakeコマンドでビルドしているのか。という感情を得ました。
FHSの概念
ubuntuのファイル構成、どうなってるんだろ。とだれもが思うはず。
このあたりの理解が深まった感覚はあります。
/optと、usr/local, usr/src 皆さんお答えできますか?
ノック練習をしてみるといいです。
おまけ
GoやSwift、Rustは自己ホスティング化というのを使っているらしい。
ここがとんでもなく難しいらしく、私は事故しそうなのでそっと閉じておきました。
あと、依存関係回り、難しすぎて、コツコツ日々学習が必要な項目だと思いました。
Discussion