After my attempts to make a binhost resulted in a overcomplex mess that myself could not maintain, time for a more simplified approach: just let the hosts use emerge as usual, but delegate the heavy lifting to a more powerful machine.

Enter distcc. It might be a bit slower than a perfectly tuned binhost, but it is much easier to set up.

In this guide, we will walk through setting up a Gentoo client and server using OpenRC and IPv6. Please, for the love of all saints and martys, learn IPv6, let IPv4 die in peace.

Step 1: Setting Up the Build Server

First, we need to prepare the machine that will do the heavy lifting.

  1. Install the software: Run emerge --ask sys-devel/distcc on your server.

  2. Configure the daemon: Open the configuration file with nano /etc/conf.d/distccd. Since we are living in the future, we are using IPv6 ULA addresses for our local network.

    Add the following line (I have randomized the address for this example): DISTCCD_OPTS="${DISTCCD_OPTS} --listen fd98:7654:3210:1:abcd:ef01:2345:6789 --allow fd98:7654:3210:1::/64"

  3. Start the service: Tell OpenRC to start the service at boot and then start it immediately:

    rc-update add distccd default
    rc-service distccd start
    

That is it for the server! One perk of using IPv6 ULA is that you generally don’t have to worry about firewall headaches.

Step 2: Configuring the Client

Now, let’s tell your local machine to start offloading work.

  1. Install distcc: Run emerge --ask sys-devel/distcc on your client machine.

  2. Set the host: Tell the client where the server lives: distcc-config --set-hosts "localhost [fd98:7654:3210:1:abcd:ef01:2345:6789]"

  3. Edit make.conf: Open /etc/portage/make.conf and add these lines:

    FEATURES="distcc"
    MAKEOPTS="-j8"
    

    Note: Set -j8 to the number of CPUs available on your build server.

The “Native” Trap: Handling CPU Flags

Here is a common pitfall: the native flag does not work with distcc. If your client has a different CPU than the server, the build will fail or crash. You must inline the flags for your client’s specific architecture.

I recommend using app-misc/resolve-march-native to find the right settings. Run it, and it will give you a string like this: -march=znver3 -mshstk --param=l1-cache-line-size=64 --param=l1-cache-size=32 --param=l2-cache-size=512

Take that output and add it directly to your COMMON_FLAGS in make.conf: COMMON_FLAGS="-O2 -march=znver3 -mshstk --param=l1-cache-line-size=64 --param=l1-cache-size=32 --param=l2-cache-size=512 -pipe"

Testing and Monitoring

Ready to see if it works? Try a quick build: emerge --oneshot app-arch/tar

While it runs, watch your build server. You should see a massive spike in CPU usage. If you want a visual way to monitor the progress, run this as root on the server: DISTCC_DIR="/var/tmp/portage/.distcc/" distccmon-gnome &

Troubleshooting: If things go wrong, don’t panic. You can debug the client by running export DISTCC_VERBOSE=1 before your emerge command.

The Golden Rule of Updates

This is the most important part. To avoid version mismatches, you must follow a specific update order:

  1. Update the client’s GCC first.
  2. Update the build server.
  3. Update the client’s rest of the system.

To do this safely, run:

emerge --sync
emerge --oneshot sys-apps/portage
emerge --oneshot gcc

Happy compiling! With a tad less pain than keeping a binhost.