Docker for Mac内のRustでmacOS向けのプログラムを書けるようにした。
Rustのクロスコンパイルの設定ができたので、Docker for MacでmacOS用のプログラムが書けるようになってきた
— mzp (@mzp) 2017年5月2日
⭐️要約
以下のDockerfireでクロスコンパイルのできるイメージを作成できる。
FROM multiarch/crossbuild # reinstall osx cross compiler to link with SDK 10.7 ENV DARWIN_OSX_VERSION_MIN="10.7" RUN rm -rf /usr/osxcross \ && mkdir -p "/tmp/osxcross" \ && cd "/tmp/osxcross" \ && curl -sLo osxcross.tar.gz "https://codeload.github.com/${OSXCROSS_REPO}/tar.gz/${OSXCROSS_REVISION}" \ && tar --strip=1 -xzf osxcross.tar.gz \ && rm -f osxcross.tar.gz \ && curl -sLo tarballs/MacOSX${DARWIN_SDK_VERSION}.sdk.tar.xz \ "${DARWIN_SDK_URL}" \ && yes "" | SDK_VERSION="${DARWIN_SDK_VERSION}" OSX_VERSION_MIN="${DARWIN_OSX_VERSION_MIN}" ./build.sh \ && mv target /usr/osxcross \ && mv tools /usr/osxcross/ \ && ln -sf ../tools/osxcross-macports /usr/osxcross/bin/omp \ && ln -sf ../tools/osxcross-macports /usr/osxcross/bin/osxcross-macports \ && ln -sf ../tools/osxcross-macports /usr/osxcross/bin/osxcross-mp \ && rm -rf /tmp/osxcross \ && rm -rf "/usr/osxcross/SDK/MacOSX${DARWIN_SDK_VERSION}.sdk/usr/share/man" # install toolchain RUN curl https://sh.rustup.rs -sSf | sh -s -- --default-toolchain stable -y ENV PATH=/root/.cargo/bin:$PATH # install target RUN rustup target add x86_64-apple-darwin WORKDIR /work
カレントディレクトリに hello.rs
を配置した上で、以下のコマンドを実行すると、macOS向けのバイナリが生成される。
docker build -t rust-cross-compile . docker run -v $PWD:/work -it -e CROSS_TRIPLE=x86_64-apple-darwin rust-cross-compile rustc --target=x86_64-apple-darwin hello.rs
📝調べたこと
上記のDockerfileを書くまでに調べたことをメモしておく。
標準ライブラリ
macOS向けにビルドされた標準ライブラリをインストールする。 これは rustup
から行なえる。
$ rustup target add x86_64-apple-darwin info: downloading component 'rust-std' for 'x86_64-apple-darwin' info: installing component 'rust-std' for 'x86_64-apple-darwin'
リンカ
リンカがMach-O形式を理解しないので、ビルドできずエラーになる。
$ rustc --target=x86_64-apple-darwin hello.rs error: linking with `cc` failed: exit code: 1 | (snip) = note: hello.0.o: file not recognized: File format not recognized collect2: error: ld returned 1 exit status error: aborting due to previous error
multiarch/crossbuildが各ターゲットのツールチェインを含んでいるのでこれを使うようにする。 このイメージには crossbuild
というツールチェインを切り替えるシェルスクリプトが含まれているので、これを使うようにする。
CROSS_TRIPLE=x86_64-apple-darwin crossbuild rustc --target=x86_64-apple-darwin hello.rs
macOS向けの設定
標準ライブラリは OSX 10.7 向けにビルドされているが、multiarch/crossbuild に含まれるリンカは 10.6向けのものなので、うまくビルドできない。
CROSS_TRIPLE=x86_64-apple-darwin crossbuild rustc --target=x86_64-apple-darwin hello.rs error: linking with `cc` failed: exit code: 1 | (snip) ld: warning: object file (...) was built for newer OSX version (10.7) than being linked (10.6) ld: targeted OS version does not support use of thread local variables in __ZN4core6result13unwrap_failed17h374a94f6b7a942a9E for architecture x86_64 clang: error: linker command failed with exit code 1 (use -v to see invocation) error: aborting due to previous error
そのため、macOS向けのツールチェインを再ビルドする。
export DARWIN_OSX_VERSION_MIN="10.7" rm -rf /usr/osxcross \ && mkdir -p "/tmp/osxcross" \ && cd "/tmp/osxcross" \ && curl -sLo osxcross.tar.gz "https://codeload.github.com/${OSXCROSS_REPO}/tar.gz/${OSXCROSS_REVISION}" \ && tar --strip=1 -xzf osxcross.tar.gz \ && rm -f osxcross.tar.gz \ && curl -sLo tarballs/MacOSX${DARWIN_SDK_VERSION}.sdk.tar.xz \ "${DARWIN_SDK_URL}" \ && yes "" | SDK_VERSION="${DARWIN_SDK_VERSION}" OSX_VERSION_MIN="${DARWIN_OSX_VERSION_MIN}" ./build.sh \ && mv target /usr/osxcross \ && mv tools /usr/osxcross/ \ && ln -sf ../tools/osxcross-macports /usr/osxcross/bin/omp \ && ln -sf ../tools/osxcross-macports /usr/osxcross/bin/osxcross-macports \ && ln -sf ../tools/osxcross-macports /usr/osxcross/bin/osxcross-mp \ && rm -rf /tmp/osxcross \ && rm -rf "/usr/osxcross/SDK/MacOSX${DARWIN_SDK_VERSION}.sdk/usr/share/man"
ビルド
これでビルドできるる。
$ CROSS_TRIPLE=x86_64-apple-darwin crossbuild rustc --target=x86_64-apple-darwin hello.rs $ file hello hello: Mach-O 64-bit x86_64 executable