Distcc/Cross-Compiling

From Gentoo Wiki
< Distcc
Jump to:navigation Jump to:search
This page is a translated version of the page Distcc/Cross-Compiling and the translation is 37% complete.


このガイドでは、異なるプロセッサアーキテクチャ間でクロスコンパイルするために distcc をセットアップする方法を示します。

distcc によるクロスコンパイル

はじめに

distcc は、ネットワークに接続された複数のコンピュータ間でソフトウェアのコンパイルの負担を分散できるツールです。 ネットワーク接続されたボックスがすべて、同じプロセッサ アーキテクチャ用に構築された同じツールチェーンを使用している限り、特別な distcc セットアップは必要ありません。

このガイドでは、さまざまなアーキテクチャ向けにコンパイルするように distcc を構成する方法について説明します。

必要なユーティリティを emerge する

まず、コンパイルプロセスに関与するすべてのマシン上でcrossdevをemergeする必要があります。 crossdev は、クロスアーキテクチャ ツールチェーンの構築を簡単にするツールです。 その使用法は簡単です。crossdev -t sparc は、Sparc アーキテクチャを対象とした完全なクロスツールチェーンを構築します。 これには、binutils、gcc、glibc、および linux-headers が含まれます。

すべてのヘルパー ボックスで適切なクロスツールチェーンを出現させる必要があります。 さらにヘルプが必要な場合は、crossdev --help を実行してみてください。

クロスツールチェーンを微調整したい場合は、ヘルパー ボックス上でビルドされるクロス開発パッケージの正確なバージョンを含むコマンド ラインを生成するスクリプトを次に示します (スクリプトはターゲット ボックス上で実行されます)。

コード Script to fine-tune cross development tools
#!/bin/bash
BINUTILS_VER=$(qatom -F '%{PV}' $(qfile -v $(realpath /usr/bin/ld) | cut -d' ' -f1))
GCC_VER=$(qatom -F '%{PV}' $(qfile -v $(realpath /usr/bin/gcc) | cut -d' ' -f1))
KERNEL_VER=$(qatom -F '%{PV}' $(qlist -Ive sys-kernel/linux-headers))
LIBC_VER=$(qatom -F '%{PV}' $(qlist -Ive sys-libs/glibc))
echo "crossdev --b '~${BINUTILS_VER}' --g '~${GCC_VER}' --k '~${KERNEL_VER}' --l '~${LIBC_VER}' -t $(portageq envvar CHOST)"

Next, you will need to emerge distcc on all the machines that will be involved in the process. This includes the box that will run emerge and the boxes with the cross-compilers. Please see the Gentoo Distcc Documentation for more information on setting up and using distcc.

メモ
Current versions of crossdev have a -S (--stable) flag for installing only stable versions of compiler tools. (ie. crossdev -t i686-pc-linux-gnu --stable --ex-gcc --ex-gdb --portage --pretend). Without this option, crossdev installs the latest experimental compiler tools packages! Otherwise, the above script is no longer needed, unless specific versions of package tools and/or headers have been unmasked.

アーキテクチャ固有のメモ

メモ
Obtain the architecture name by looking at the compile target's CHOST variable within /etc/make.conf. When mangling the architecture name for the crossdev -t option, crossdev will merrily guess and install tools using the mangled architecture name for folder names within /usr (ie. /usr/i686-pc-linux-gnu/, /usr/i686-linux-gnu/, ...). To resolve this, specify each mangled architecture/folder name to crossdev --clean for uninstalling, or manually remove the folders from the system.

Intel x86 サブアーキテクチャ群

If you are cross-compiling between different subarchitectures for Intel x86 (e.g. i586 and i686), you must still build a full cross-toolchain for the desired CHOST, or else the compilation will fail. This is because i586 and i686 are actually different CHOSTs, despite the fact that they are both considered "x86." Please keep this in mind when you build your cross-toolchains. For example, if the target box is i586, this means that you must build i586 cross-toolchains on your i686 helper boxes.

SPARC

Using crossdev -t sparc might fail with one of the following errors:

コード Errors displayed when running crossdev -t sparc
linker with -z relro support required
support for the tls_model attribute is required
this configuration requires -mlong-double-128 support

If this happens, try using the following command instead:

user $crossdev --lenv "CC=sparc-unknown-linux-gnu-gcc" -t sparc-unknown-linux-gnu

Configuring distcc to cross-compile correctly

メモ
The workaround as described in this section is not needed any more since distcc-3.2, as the functionality for replacing the calls to the compiler with the full compiler name has since then been implemented in distcc itself.

In the default distcc setup, cross-compiling will not work properly. The problem is that many builds just call gcc instead of the full compiler name (e.g. sparc-unknown-linux-gnu-gcc). When this compile gets distributed to a distcc helper box, the native compiler gets called instead of your shiny new cross-compiler.

Fortunately, there is a workaround for this little problem. All it takes is a wrapper script and a few symlinks on the box that will be running emerge. We'll use a Sparc box as an example. Wherever you see sparc-unknown-linux-gnu below, you will want to insert your own CHOST value (x86_64-pc-linux-gnu for an AMD64 box, for example). When you first emerge distcc, the /usr/lib/distcc/bin directory looks like this:

メモ
The following instructions are to be performed only on the box running the emerge. Do not perform these steps on the helper boxes.
root #cd /usr/lib/distcc/bin
root #ls -l
total 0
lrwxrwxrwx  1 root root 15 Dec 23 20:13 c++ -> /usr/bin/distcc
lrwxrwxrwx  1 root root 15 Dec 23 20:13 cc -> /usr/bin/distcc
lrwxrwxrwx  1 root root 15 Dec 23 20:13 g++ -> /usr/bin/distcc
lrwxrwxrwx  1 root root 15 Dec 23 20:13 gcc -> /usr/bin/distcc
lrwxrwxrwx  1 root root 15 Dec 23 20:13 sparc-unknown-linux-gnu-c++ -> /usr/bin/distcc
lrwxrwxrwx  1 root root 15 Dec 23 20:13 sparc-unknown-linux-gnu-g++ -> /usr/bin/distcc
lrwxrwxrwx  1 root root 15 Dec 23 20:13 sparc-unknown-linux-gnu-gcc -> /usr/bin/distcc

Here is what you want to do:

root #rm c++ g++ gcc cc

Next, we'll create the new script on this box. Fire up your favorite editor and create a file with the following text in it, then save it as sparc-unknown-linux-gnu-wrapper. Remember to change the CHOST value (in this case, sparc-unknown-linux-gnu) to the actual CHOST of the box that will be running the emerge.

コード The new wrapper script
#!/bin/bash
exec /usr/lib/distcc/bin/sparc-unknown-linux-gnu-g${0:$[-2]} "$@"

Next, we'll make the script executable and create the proper symlinks:

root #chmod a+x sparc-unknown-linux-gnu-wrapper
root #ln -s sparc-unknown-linux-gnu-wrapper cc
root #ln -s sparc-unknown-linux-gnu-wrapper gcc
root #ln -s sparc-unknown-linux-gnu-wrapper g++
root #ln -s sparc-unknown-linux-gnu-wrapper c++

When you're done, /usr/lib/distcc/bin will look like this:

root #ls -l
total 4
lrwxrwxrwx  1 root root 25 Jan 18 14:20 c++ -> sparc-unknown-linux-gnu-wrapper
lrwxrwxrwx  1 root root 25 Jan 18 14:20 cc -> sparc-unknown-linux-gnu-wrapper
lrwxrwxrwx  1 root root 25 Jan 18 14:20 g++ -> sparc-unknown-linux-gnu-wrapper
lrwxrwxrwx  1 root root 25 Jan 18 14:20 gcc -> sparc-unknown-linux-gnu-wrapper
lrwxrwxrwx  1 root root 15 Nov 21 10:42 sparc-unknown-linux-gnu-c++ -> /usr/bin/distcc
lrwxrwxrwx  1 root root 15 Nov 21 10:42 sparc-unknown-linux-gnu-g++ -> /usr/bin/distcc
lrwxrwxrwx  1 root root 15 Jul 27 10:52 sparc-unknown-linux-gnu-gcc -> /usr/bin/distcc
-rwxr-xr-x  1 root root 70 Jan 18 14:20 sparc-unknown-linux-gnu-wrapper
メモ
With new distcc versions, the following steps are unnecessary—you can emerge distcc on the client with the crossdev USE flag set instead to achieve the same result.

Next we want to make sure that these wrappers stay available after upgrading the distcc package as it will overwrite the symbolic links. We can do this through a /etc/portage/bashrc file that looks like so:

ファイル /etc/portage/bashrc
case ${CATEGORY}/${PN} in
                 sys-devel/distcc | sys-devel/gcc | sys-devel/clang)
			if [ "${EBUILD_PHASE}" == "postinst" ]; then
				/usr/local/sbin/distcc-fix &
			fi
		;;
esac

Then create one of the following files as applicable. If you are not using clang:

ファイル /usr/local/sbin/distcc-fix
#!/bin/bash                     
sleep 20
# We extract $TUPLE from make.conf to avoid editing the script for each architecture.
TUPLE=$(portageq envvar CHOST)
GCC_VER=$(gcc-config -c|cut -d "-" -f5)
cd /usr/lib/distcc/bin
rm cc c++ gcc g++ gcc-${GCC_VER} g++-${GCC_VER} ${TUPLE}-wrapper
echo '#!/bin/bash' > ${TUPLE}-wrapper
echo "exec ${TUPLE}-g\${0:\$[-2]}" "\"\$@\"" >> ${TUPLE}-wrapper
chmod 755 ${TUPLE}-wrapper
ln -s ${TUPLE}-wrapper cc
ln -s ${TUPLE}-wrapper c++
ln -s ${TUPLE}-wrapper gcc
ln -s ${TUPLE}-wrapper g++
ln -s ${TUPLE}-wrapper gcc-${GCC_VER}
ln -s ${TUPLE}-wrapper g++-${GCC_VER}

If you ARE using clang:

ファイル /usr/local/sbin/distcc-fix
#!/bin/bash	                
#clang aware, now your >chromium-65 ebuilds will use distcc just like before ;) 
sleep 20
# We extract $TUPLE from make.conf to avoid editing the script for each architecture.
TUPLE=$(portageq envvar CHOST)
GCC_VER=$(gcc-config -c|cut -d "-" -f5)
CLANG_VER=$(clang --version|grep version|cut -d " " -f3|cut -d'.' -f1,2)
cd /usr/lib/distcc/bin
rm cc c++ gcc g++ gcc-${GCC_VER} g++-${GCC_VER} clang clang++ clang-${CLANG_VER} clang++-${CLANG_VER} ${TUPLE}-wrapper ${TUPLE}-clang-wrapper 
echo '#!/bin/bash' > ${TUPLE}-wrapper
echo "exec ${TUPLE}-g\${0:\$[-2]}" "\"\$@\"" >> ${TUPLE}-wrapper
echo '#!/bin/bash' > ${TUPLE}-clang-wrapper
echo "exec ${TUPLE}-\$(basename \${0}) \"\$@\"" >> ${TUPLE}-clang-wrapper
chmod 755 ${TUPLE}-wrapper
chmod 755 ${TUPLE}-clang-wrapper
ln -s ${TUPLE}-wrapper cc
ln -s ${TUPLE}-wrapper c++
ln -s ${TUPLE}-wrapper gcc
ln -s ${TUPLE}-wrapper g++
ln -s ${TUPLE}-wrapper gcc-${GCC_VER}
ln -s ${TUPLE}-wrapper g++-${GCC_VER}
ln -s ${TUPLE}-clang-wrapper clang
ln -s ${TUPLE}-clang-wrapper clang++
ln -s ${TUPLE}-clang-wrapper clang-${CLANG_VER}
ln -s ${TUPLE}-clang-wrapper clang++-${CLANG_VER}

Give it the proper permissions:

root #chmod 755 /usr/local/sbin/distcc-fix

Congratulations; you (hopefully) now have a working cross-distcc setup.

How this works

When distcc is called, it checks to see what it was called as (e.g. i686-pc-linux-gnu-gcc, sparc-unknown-linux-gnu-g++, etc.) When distcc then distributes the compile to a helper box, it passes along the name it was called as. The distcc daemon on the other helper box then looks for a binary with that same name. If it sees just gcc, it will look for gcc, which is likely to be the native compiler on the helper box, if it is not the same architecture as the box running emerge. When the full name of the compiler is sent (e.g. sparc-unknown-linux-gnu-gcc), there is no confusion.

トラブルシューティング

This section covers a number of common problems when using distcc for cross-compiling.

Remote host distccd COMPILE ERRORS

When receiving the message COMPILE ERRORS within a remote host's /var/log/distccd.log file, see the above notes concerning specifying the correct architecture name (ie. crossdev -t $TARGET).

Another solution is to uninstall and re-install crossdev compiler tools, using the crossdev --clean option, or ensuring /usr/$TARGET no longer exists, and then completely reinstall the cross compiler.

It might also be wise to edit the remote host's /usr/$TARGET/etc/portage/make.conf, and ensure the contents of the CFLAGS variable are similar on all computers or hosts performing compiler operations. Also make sure the USE flags for the cross compiler are sufficient: if you built GCC with USE=graphite on the client, you need a line like cross-i686-pc-linux-gnu/gcc graphite in /etc/portage/package.use too.

Failed to exec $TARGET-unknown-linux-gnu-gcc: No such file or directory

The wrapper scripts might fail to execute, even with correct permissions:

コード Error message from wrapper
distcc[6195] (dcc_execvp) ERROR: failed to exec i686-unknown-linux-gnu-gcc: No such file or directory)

To resolve this, make sure to have the wrapper script created with the complete name of the architecture target:

user $ls -alh /usr/lib/distcc/bin/c++
/usr/lib/distcc/bin/c++ ->./i686-pc-linux-gnu-wrapper

関連項目

  • Crossdev — a set of bash scripts that utilize emerge to provide a system integrated cross-compilation capability.

This page is based on a document formerly found on our main website gentoo.org.
The following people contributed to the original document: Andrew Gaffney, Joshua Saddler
They are listed here because wiki history does not allow for any external attribution. If you edit the wiki article, please do not add yourself here; your contributions are recorded on each article's associated history page.