HOMCC, pronounced həʊm siː siː, is a work from home oriented, compilation distribution project which keeps the premise of always generating the same results as a local build.
Current supported languages are C and C++ with their respective gcc and clang compilers.
While distributing compilations generally improves build times of large code bases, narrow network bandwidths pose a crucial limiting factor.
This project's primary goal is to find approaches to mitigate this bottleneck.
Compared to distcc, HOMCC provides compilation times smaller by some orders of magnitudes for connections with a small uplink:
Difference in total remote compilation times for a Celonis internal C++ code base built with clang++-14, a total server job limit of 112 and 60 compilation threads.
The main solution to enable faster compilation times for thinner connections is the compression and server-side caching of dependencies.
Due to caching, only missing dependencies are requested from clients which drastically decreases the overall network traffic once the cache is warmed up.
Transmitted files like the requested dependencies and also the resulting object files are compressed to further improve build times.
Additionally, HOMCC provides sandboxed compiler execution for remote compilations via schroot and docker.
- Download the latest release or build the Debian packages yourself
- The
homccclient and thehomccdserver both depend on the sharedpython3-homcc-commonpackage. Keep all.debfiles in the same directory soaptcan resolve that dependency automatically. - Install the
homccclient via:$ sudo apt install ./homcc_*.deb ./python3-homcc-common_*.deb
- Install the
homccdserver via:$ sudo apt install ./homccd_*.deb ./python3-homcc-common_*.deb
- Follow the client Installation guide
- Find usage description and
homccdefaults:$ homcc --help
- Use
homccby specifyingCCACHE_PREFIX=homccin yourconanprofile or IDE of choice! - Specify your remote compilation server via the
$HOMCC_HOSTSenvironment variable or in a dedicatedhostsfile:
hostsfile locations$HOMCC_DIR/hosts
~/.homcc/hosts
~/.config/homcc/hosts
/etc/homcc/hosts - Possible
hostsformats:HOSTformat:HOST: TCP connection to specifiedHOSTwith default port3126HOST:PORT: TCP connection to specifiedHOSTwith specifiedPORT
@HOST/USER@HOSTformat:- Connect to
HOSTthrough an SSH tunnel instead of a plain TCP connection, optionally authenticating asUSER homccestablishes a multiplexed SSH master connection toHOSTand local-forwards a port to thehomccdrunning there; the daemon only needs to listen on the remote loopback interface (e.g.--listen=127.0.0.1). Subsequent compilations reuse the master connection (OpenSSHControlMaster/ControlPersist), so the per-compilation cost stays close to a plain TCP connection- The daemon's port on the remote defaults to
3126and can be overridden with@HOST:PORT(use@[IPv6]:PORTfor IPv6 addresses) - Authentication relies on your existing SSH setup (keys/agent);
homccdoes not manage SSH credentials itself
- Connect to
HOST/LIMITformat:- Define any of the above
HOSTformats with an additionalLIMITparameter that specifies the maximum connection limit to the correspondingHOST - It is advised to always specify your
LIMITs as they will otherwise default to 2 and only enable minor levels of concurrency
- Define any of the above
HOST,COMPRESSIONformat:- Define any of the above
HOSTorHOST/LIMITformat with an additionalCOMPRESSIONalgorithm information - Choose from:
lzo: Lempel-Ziv-Oberhumer compression algorithmlzma: Lempel-Ziv-Markov chain algorithm
- No compression is used per default, specifying
lzois however advised
- Define any of the above
Example: hostsExplanation # homcc: hosts localhost remotehost/12 192.168.0.1:3126/21 [FC00::1]:3126/42,lzo @buildhost/24,lzo user@buildhost:3126/24
# Comment "localhost" host with default limit of 2 Named "remotehost" TCP host with limit of 12 at default port 3126 IPv4 "192.168.0.1" TCP host at port 3126 with limit of 21 IPv6 "FC00::1" TCP host at port 3126 with limit of 42 and lzo compression "buildhost" via SSH tunnel with limit of 24 and lzo compression "buildhost" via SSH tunnel as user "user", daemon port 3126, limit of 24
- [Optional] Sandboxed execution via either
schrootordockercan be enabled by specifying their respective environmental variablesHOMCC_SCHROOT_PROFILEandHOMCC_DOCKER_CONTAINER, e.g.:There is also the possibility to use CLI arguments or config files to specify sandboxed execution, see Configuration. Utilizable profile and container names need to be provided by the administrator of the relevant host server.$ HOMCC_SCHROOT_PROFILE=jammy homcc g++ foo.cpp
-
Follow the server Installation guide
-
Find usage description and server defaults:
$ homccd --help
-
[Optional] Sandboxed execution:
schroot: Set up yourschrootenvironments at/etc/schroot/schroot.confor in the/etc/schroot/chroot.d/directory and mount the/tmp/directory to enable sandboxed compiler execution.docker:- Make sure that the docker containers that you want to compile in have mounted the host's
/tmpdirectory to/tmp(this is necessary to access cached dependencies):$ sudo docker run --name example_container -v /tmp:/tmp -dit ubuntu:22.04
- Make sure the docker containers you want to compile in are running and have the appropriate compilers installed
- Make sure that the docker containers that you want to compile in have mounted the host's
-
Cross compilation:
- For both
gccandclang,homccwill remap the compiler name to the client's target triple, i.e.g++on the client becomesx86_64-linux-gnu-g++when there is a difference in the target triple between client and server. Make sure that you create such a symlink on the server, so that it links togcc/clang. - For
clang,homccadditionally adds the--target={target_triple}option to the server compile command. Using clang configuration files, you can specify different arguments per cross compilation target, e.g. differentsysroots.
- For both
-
Overwrite defaults globally via specifying environmental variables with the
HOMCC_orHOMCCD_prefix or viahomcc.confconfiguration files:homcc.conffile locations$HOMCC_DIR/homcc.conf
~/.homcc/homcc.conf
~/.config/homcc/homcc.conf
/etc/homcc/homcc.conf -
❗ Explicit configuration is currently not necessary, only do this if you know exactly what you are doing!
Environmental Variable Example: homcc.confExplanation # homcc HOMCC_COMPRESSION HOMCC_SCHROOT_PROFILE HOMCC_DOCKER_CONTAINER HOMCC_COMPILATION_REQUEST_TIMEOUT HOMCC_ESTABLISH_CONNECTION_TIMEOUT HOMCC_REMOTE_COMPILATION_TRIES HOMCC_LOG_LEVEL HOMCC_VERBOSE HOMCC_NO_LOCAL_COMPILATION HOMCC_SSH_EXECUTABLE HOMCC_SSH_CONTROL_PERSIST HOMCC_SSH_OPTIONS # homccd HOMCCD_LIMIT HOMCCD_PORT HOMCCD_ADDRESS HOMCCD_LOG_LEVEL HOMCCD_VERBOSE HOMCC_MAX_DEPENDENCY_CACHE_SIZE
[homcc] compression=lzo schroot_profile=jammy docker_container=example_container compilation_request_timeout=120 establish_connection_timeout=10 remote_compilation_tries=3 log_level=DEBUG verbose=True no_local_compilation=True ssh_executable=ssh ssh_control_persist=600 ssh_options=-o BatchMode=yes [homccd] limit=64 port=3126 address=0.0.0.0 log_level=DEBUG verbose=True max_dependency_cache_size=10G
# Client configuration Default compression algorithm: {lzo, lzma} Profile to specify the schroot environment for remote compilations Docker container that should be used on the server for remote compilations Total timeout value to wait for a remote compilation request in seconds Timeout value to wait for establishing a connection to a remote compilation server Maximal amount of remote compilation servers that are requested from for a single compilation Detail level for log messages: {DEBUG, INFO, WARNING, ERROR, CRITICAL} Enable verbosity mode which implies detailed and colored logging Enforce that even on recoverable failures no local compilation is executed Executable used to establish SSH tunnels for '@HOST'/'USER@HOST' hosts Seconds an idle multiplexed SSH master connection is kept alive for reuse Additional options passed to the SSH executable, e.g. '-o' flags # Server configuration Maximum limit of concurrent compilations TCP port to listen on IP address to listen on Detail level for log messages: {DEBUG, INFO, WARNING, ERROR, CRITICAL} Enable verbosity mode which implies detailed and colored logging Maximum size of the dependency cache. You must specify either 'M' (Mebibyte) or 'G' (Gibibyte) as suffix.
Things to keep in mind when deploying homccd:
homccdoes not support built-in transport encryption such as TLS: plain TCP hosts transmit source files unencrypted, so a VPN is required over untrusted networks. Alternatively, use an SSH host (@HOST/USER@HOST) to tunnel the connection through an encrypted, authenticated SSH channel to ahomccdbound to the remote loopback interface.homccddoes not limit simultaneous connections of a single client. A malicious client could therefore block the service by always opening up connections until no server slots are available any more.homccddoes not limit access to docker containers or chroot environments. A client can choose any docker container or chroot environment available on the server to execute the compilation in.
❗ The key takeaway of the previous points is to not expose homccd publicly. Make sure only internal users (e.g. developers) have access to the service, for example through a VPN or by only accepting SSH-tunneled connections.
- Install the
liblzo2-devapt package (needed for LZO compression):$ sudo apt install liblzo2-dev liblzma-dev
- Install required dependencies:
$ python -m pip install -r requirements.txt
- Tests and test coverage analysis are performed via pytest
- Execute all default tests in
./tests/and perform test coverage:$ pytest -v -rfEs --cov=homcc
- The
homccclient uses SysV semaphores. To view currently open semaphores, execute:$ ipcs -s
- Analyze all
pythonfiles with pylint:$ pylint -v --rcfile=.pylintrc *.py homcc tests - Check static typing of all
pythonfiles with mypy:$ mypy --pretty *.py homcc tests
- Formatting and format check are executed via black:
$ black --check --color --diff --verbose *.py homcc tests - Sorting
imports is performed by isort:$ isort --check --color --diff --gitignore --verbose *.py homcc tests
- The packages are built from the hand-written
debian/directory using the standarddebhelper/dh-pythontooling. Install the required tools:$ sudo apt install -y \ debhelper dh-python devscripts fakeroot \ python3-all python3-setuptools \ liblzo2-dev
- Run
make(ormake all) to build all packages, or directly:$ dpkg-buildpackage -rfakeroot -uc -us -b
- This produces three
.debfiles from the single source package:homcc— the clienthomccd— the server, including itssystemdservicepython3-homcc-common— the shared code both packages depend on
dpkg-buildpackagewrites its artifacts to the parent directory;makeadditionally copies the resulting.debfiles into the./target/directory.
- Install required tools:
$ sudo apt install schroot debootstrap
- Create
schrootenvironment:- Download and install selected distribution to your desired location, e.g.
Ubuntu 22.04 Jammy Jellyfishfrom Ubuntu Releases at/var/chroot/:$ sudo debootstrap jammy /var/chroot/jammy http://archive.ubuntu.com/ubuntu
- Configure the environment by creating a corresponding file in the
/etc/schroot/chroot.d/directory or by appending an entry to/etc/schroot/schroot.conf, e.g. by replacingUSERNAMEforjammy.conf:[jammy] description=Ubuntu 22.04 Jammy Jellyfish directory=/var/chroot/jammy root-users=USERNAME users=USERNAME type=directory
- Download and install selected distribution to your desired location, e.g.
- Verify that a
jammyentry exists:$ schroot -l
- Install missing
build-essentials in the new environment (currently onlyg++is needed):$ sudo schroot -c jammy -- apt -y install build-essential
- Execute schrooted compilations by specifying
--schroot-profile=jammyvia the CLI or in thehomcc.conffile - Execute all tests in
./tests/and perform test coverage:$ pytest -v -rfEs --cov=homcc --runschroot=jammy
- Create a docker container with a working
gcccompiler, the easiest image to get is probably the officialubuntudocker image:docker run -dit --name jammy -v /tmp:/tmp ubuntu:jammy
- Execute all tests (including the docker tests by specifying
--rundocker=jammy) and perform test coverage:$ pytest -v -rfEs --cov=homcc --rundocker=jammy