• Stars
    star
    566
  • Rank 78,774 (Top 2 %)
  • Language
    Shell
  • License
    MIT License
  • Created over 9 years ago
  • Updated 4 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

System for building cross-distribution Linux binaries

Maintainers Wanted

System for building cross-distribution Linux binaries

Holy Build Box is a system for building "portable" binaries for Linux: binaries that work on pretty much any Linux distribution. This works by providing an easy-to-use compilation environment with an old glibc version. Holy Build Box can produce amd64 and arm64 binaries.

Resources:: Website | Issue tracker

Table of contents


Problem introduction

If you have ever tried to build a C/C++ Linux binary, then you will probably have noticed that it may not run on other Linux distributions, or even other versions of the same Linux distribution. This happens even if your application does not use newer APIs. This is in stark contrast to Windows binaries, which tend to on pretty much every Windows machine. There are many reasons why this is so. This section introduces you to each problem, and whether and how Holy Build Box solves that problem.

Glibc symbols

The most prominent reason why binaries aren't portable is glibc symbols. When you try to run an older Linux distribution a binary that is compiled on a newer Linux distribution, you may see an error message like this:

./foo: /lib/libc.so.6: version `GLIBC_2.11' not found

Each function in glibc -- each symbol -- actually has multiple versions. This allows the glibc developers to change the behavior of a function without breaking backwards compatibility with applications that happen to rely on bugs or implementation-specific behavior. During the linking phase, the linker "helpfully" links against the most recent version of the symbol. The thing is, glibc introduces new symbol versions very often, resulting in binaries that will most likely depend on a recent glibc.

The only way to tell the compiler and linker to use older symbol versions is by using linker scripts. However, this requires you to specify the version for each and every symbol, which is an undoable task.

Holy Build Box solves the glibc symbol problem by providing a tightly-controlled build environment that contains an old version of glibc.

Why statically linking to glibc is a bad idea

The glibc symbol problem can be solved by statically linking to glibc. However, this is not the approach that Holy Build Box advocates. Statically linking to glibc wastes a lot of space. A simple 200 KB program can suddenly become 5 MB.

Statically linking to glibc also introduces various runtime problems. For example, such binaries are not able to call dlopen(), so applications which want to load plugins at runtime aren't compatible with this approach.

Dynamic libraries

Another prominent reason why binaries aren't portable is dynamic libraries. Any non-trivial application has dependencies, but every distribution has different library versions.

It is awkward to ship a binary to users, only for them to discover that they need to install some library first before your binary works. Even if your user accepts that they need to install some library, that still does not fully solve the problem, because newer distributions may ship a newer yet binary-incompatible version of a dependency library. So just compiling your application on an older distribution is not enough.

The solution is to statically link to dependencies. Note that we are not advocating static linking of everything: the Holy Build Box approach is to statically link to all dependencies, except for glibc and other system libraries that are found on pretty much every Linux distribution, such as libpthread and libm.

There are some problems with static linking though. Performing static linking as we advocate it, is very awkward on most systems for the following reasons:

  1. Many build system tools are only designed with dynamic linking in mind, and require many tweaks before they work with static linking.

    Example: the default OpenSSL pkg-config entries do not work with static linking at all.

  2. If the build environment is not tightly controlled, then various build systems may pull in too many dependencies.

    Example: suppose that you have installed libssh on your workstation because some utility application that you use requires it. Now suppose that you are trying to produce a portable binary of some third-party application. That application's build system automatically detects whether libssh is installed, and if so, links to it. However, you do not want that application to have SSH functionality. To produce the desired binary, you now need to uninstall libssh, thereby breaking the utility application that you are using.

  3. The static libraries provided by your distribution may not be compiled with the flags you want.

Holy Build Box solves problem #2 by providing a tightly-controlled build environment that is isolated from your host environment. This works through Docker: Holy Build Box is a Docker image.

Holy Build Box partially solves problem #1 and #3 by providing static versions of often-used libraries that tend to be a pain to set up for proper static linking. Holy Build Box even provides multiple versions of these libraries, compiled with different compilation flags.

Features

Isolated build environment based on Docker and CentOS 7

The Holy Build Box environment is built on CentOS 7. This allows it to produce binaries that work on pretty much any amd64 or arm64 Linux distribution released since 2015. The only currently-prominent Linux distribution that the produced binaries may not run on, is Alpine Linux. See the FAQ entry.

The environment is bare-bones with almost nothing installed. Besides the basics, only a compiler toolchain is provided. The toolchain is more recent than the one provided by CentOS 7.

  • GCC 9.3.1 (C and C++ support; in particular, C++14 is supported)
  • GNU make
  • autoconf 2.69
  • automake 1.13.4
  • libtool 2.4.2
  • pkg-config 0.29.2
  • ccache 3.7.12
  • CMake 3.19.3
  • Python 2.7.5 (+ setuptools and pip)

Included static libraries

Holy Build Box also includes static versions of certain libraries. These libraries are more recent than the ones shipped with CentOS 7.

  • zlib 1.2.11
  • OpenSSL 1.1.1i
  • curl and libcurl 7.74.0
  • SQLite 2020-3340000

These libraries are provided in multiple variants, each compiled with different compilation flags. The different variants will be covered with in Tutorial 5: Using library variants and in the Library variants guide.

Security hardening

Holy Build Box makes it easy to compile your application with special security hardening features:

  • Protection against stack overflows and stack smashing
  • Extra bounds checking in common functions
  • Load time address randomization
  • Read-only global offset table

This is covered in Tutorial 5: Library variants and in the Security hardening binaries.

Featured use cases

Kallisto bioinformatics research software

Pall Melsted, part of a team of researchers from the University of Iceland and the University of California Berkeley, uses Holy Build Box to build binaries for Kallisto, their RNA transcript quantification software.

Their research software is meant to be used by other academics, so Melsted has no control over which systems their software is used on. These other academics are primarily researchers and have few system administration skills.

Holy Build Box allows Melsted's team to publish binaries that other researchers can use with few hassles. Other researchers do not have to worry about upgrading their OS, installing a new compiler or installing dependencies.

At the same time, Melsted's team can pick their favorite and most productive programming language, C++11, without worrying about which Linux systems their users use. Melsted's team also does not have to think about publishing different binaries/packages for all the different Linux systems their users may be using.

Traveling Ruby

Traveling Ruby is a system for producing self-contained Ruby application packages for Windows, Linux and macOS. You could think of it as the Holy Build Box equivalent for Ruby applications.

Traveling Ruby works by providing precompiled Ruby binaries that work on any Linux system. Ruby developers can then take our binaries, bundle it with their application code, and distribute the result as a single zip or tar.gz file to end users. This way, end users do not have to install Ruby in order to use their applications.

The Linux binaries published by the Traveling Ruby project are produced with Holy Build Box.

Passenger web app server

Phusion Passenger is a web app server that lets you launch, operate, optimize and protect web apps, microservices & APIs. It aims to be as easy to use as possible, meaning that it has to be easy to install as well.

Passenger provides Debian and RPM packages which covers most of their users. However there still remain a significant amount of users that are not able to use Debian and RPM packages, but that still want or need binaries. One such user group is Heroku users: it is not feasible to compile Passenger on Heroku. So Heroku users use the precompiled Passenger binaries instead.

Getting started

Tutorials:

Guides:

Caveats:

FAQ

Who should be interested in portable Linux binaries?

Holy Build Box is made for developers that fit the following criteria:

  • You want to distribute binaries for your C/C++ applications to end users.
  • There are many people in your userbase with low to medium system administration skill, and you want your users to be able to easily use your applications, so you want to avoid asking them to compile from source.
  • You are wary of having to invest a disproportionate amount of time into building platform-specific packages. You want something that works for the majority of your users, without having to invest too much time.
  • You want your users to be easily able to use the latest versions of your software, so waiting for distributions to package your application is not an option.

If you identify with all of the above points, then Holy Build Box is for you.

Intepreted applications whose interpreters are written in C or C++ -- such as Ruby, Python or Node.js -- are also supported, though indirectly.

Some non-developers (i.e. users) may object to the idea of distributing portable binaries. A common objecting is as follows:

"Applications should be packaged through the distribution's native packaging system. Everything else is either broken, inconvenient or insecure."

Packaging applications using distributions' native packaging systems requires a lot of investment from the developer, both in time and in system resources. Many of them are poorly documented. For example, documentation on making Debian packages is hard to find, scattered all over the place, is poorly-written, it often outdated and is hard to understand. On top of that, complying to distributions' packaging guidelines is a lot of work, even more than learning about the packaging system in the first place.

If you are a purist, then you may not care how much time a developer has to invest. You may believe that your native packaging system is the only correct way. That is a valid stand point, but please consider that this stand point may not seem so reasonable to developers. Developers have to target a lot more users than just you. The task soon becomes unwieldly for the developer when they have to invest a huge amount of time into 3 different packaging systems and 12 different distribution versions. It is also not fun for the developer.

We at Phusion spent 3 months trying to package the Passenger application server for Debian and Ubuntu. We spent another 2 months doing the same for Red Hat distributions. Altogether, we spent 5 months during which we did not fix a single bug or introduce a single feature.

We think that distributing portable binaries is a reasonable tradeoff. For all but the most hardcore system administrators who insist on native packages, portable binaries is good enough. Hardcore system administrators are of course still free to wait until their favorite distribution has packaged the application.

Which operating systems does Holy Build Box support?

Holy Build Box only supports amd64 and arm64 Linux.

macOS is not supported. Windows is not supported. Other Unices are not supported. Other CPU architectures, such as 32 bit x86, are not supported.

Which Linux distributions do binaries compiled with Holy Build Box support?

Binaries work on pretty much any glibc-2.17-or-later-based amd64 or arm64 Linux distribution released since approx 2015. A non-exhaustive list:

  • Debian >= 8
  • Ubuntu >= 14.06
  • Red Hat Enterprise Linux >= 7
  • CentOS >= 7

Note the mention "glibc-based". Binaries may not be compatible with Linux distributions not based on glibc. For example, early versions of Alpine Linux were based on uclibc, which was not compatible with glibc at all. Later versions of Alpine Linux are based on musl, which is somewhat compatible with glibc. So produced binaries may or may not run on later versions of Alpine Linux.

Static linking introduces security problems. How do you deal with this?

We update the library versions in Holy Build Box regularly. However, application developers will need to recompile their applications on a regular basis too.

There is no way to automatically update application dependencies without recompilation, while also ensuring that their binaries are portable. The two things are mutually incompatible. There is no solution to this. (Having said that, the Meson build system follows an interesting approach which would allow you to at least automatically find out whether a binary is vulnerable.)

If you are an application developer, you should consider the tradeoff. Do your users like having a binary that Just Works(tm)? Do they like this enough that won't mind that an apt-get upgrade won't patch security issues in your application's dependencies, and that they need to wait for an update from you? Are you committed to checking your dependencies' security status and updating your binaries regularly?

How does Holy Build Box compare to using Docker to package up an application?

Docker also solves the portability problem, but it gives the application a very different feel. The application is no longer just a binary. Users will have to install Docker and will have to learn how to use Docker commands in order to use your application. Your users may not particularly care about Docker: maybe they just want to use your application without having to learn about anything else.

Docker images are much larger than binaries produced by Holy Build Box. Docker images contain entire Linux distributions and weigh in the order of hundreds of MB in the average case, or tens of MB if you really did your best to optimize things. Binaries produced by Holy Build Box can be just a few KBs.

On the other hand, compiling an application using Holy Build Box requires advanced knowledge on the C/C++ compiler toolchain. You will regularly run into situations where you need to tweak the build system a little bit before the application properly compiles with static linking. If you are not skilled at using the C/C++ compiler toolchain, then using Docker is easier because it is much more "fire and forget".

How does Holy Build Box compare to Go?

The Go compiler also produces portable Linux binaries. Holy Build Box is meant for existing C/C++ applications. In general, Go is a more productive language than C/C++. So if you are writing a new application, then using Go is an excellent choice. Otherwise, Holy Build Box is for you.

For example, the main reason why we made Holy Build Box was to be able to produce portable binaries for the Phusion Passenger application server and Traveling Ruby. Passenger is a mature codebase written in C++ so we can't just change it entirely to Go. Likewise, Ruby is written in C.

Is Holy Build Box suitable for all applications?

No. Holy Build Box is mainly designed to compile headless applications such as CLI tools, servers and daemons. For example: Phusion Passenger, Nginx, Traveling Ruby.

Supporting graphical applications such as those based on GTK, Qt, SDL, OpenGL etc is outside the scope of this project.

This is however not a technical limitation, but merely a focus one. We, the Holy Build Box maintainers, have no interest in spending time to support graphical applications, but we welcome contributors who would like to take on this challenge. Contact us if you are interested, or submit a pull request.

How should I deal with interpreted applications, such as ones written in Ruby, Python or Node.js?

We recommend that you compile the interpreter with Holy Build Box, and that you package both the interpreter and the application in a single package. If your application makes use of any interpreter extensions, then you should compile those with Holy Build Box too.

We have specific recommendations for some languages:

Ruby

Take a look at Traveling Ruby. The approach taken by Traveling Ruby is exactly what we recommended. Traveling Ruby uses Holy Build Box to build its Linux binaries.

Node.js

If your application has no dependencies on NPM modules with native extensions, then there is no need to use Holy Build Box. You can just download a Node.js binary from www.nodejs.org and package it together with your application and your npm_modules directory. The binaries shipped by www.nodejs.org are already portable and work across Linux distributions.

If your application has a dependency on an NPM module with native extension, either directly or indirectly, then you should compile Node.js and your NPM modules with Holy Build Box. When done, package the compiled Node.js, npm_modules directory and your application.

See also pkg which can bundle Node.js applications into a single portable binary.

Why the name "Holy Build Box"?

Around 2004, I (Hongli Lai) participated in a now-defunct open source project called Autopackage. Back then we were in the middle of the Linux-on-the-desktop hype. One of the things people complained most about was software installation. Every distribution had its own way of installing things, and binaries compiled on one distribution doesn't work on another. This was considered problematic because, as a developer, it is so painful to distribute software to end users. See also the FAQ entry Who should be interested in portable Linux binaries?.

This problem actually still exists -- it was never resolved.

Anyway, the Autopackage project sought to solve this problem by introducing a cross-distribution package manager. We soon realized that solving the packaging aspect only partially solved the problem. Regardless of the packaging, the binaries that were packaged still need to work across Linux distributions.

We saw that Mozilla was able to produce Firefox binaries that work on all Linux distributions. We found out that they did that by constructing a server with a special, tightly-controlled environment that contained an old glibc.

Back in 2004, virtualization was almost non-existent. All Autopackage team members were either in high school or in college. We were only barely able to afford our computers. Constructing a special server just for the purpose of compiling portable binaries was expensive: it meant buying a new computer. The entire idea of constructing such a server was so over our heads that we named Mozilla's build server a "holy build box".

We wanted to give developers a way to produce portable binaries without asking them to construct a holy build box. Virtualization was not a realistic option back then, and we could not imagine that many people would want to buy a new computer only for the purpose of producing portable binaries, especially seeing that Windows developers didn't have to do that either. So we wrote a set of scripts which automates the linker script approach. However, this approach was found to be too buggy.

Autopackage eventually went defunct because of resistance from distributors. I guess that people weren't truly interested in Linux succeeding on the desktop, despite how many people complained about it.

Fast forward to 2015. Virtualization and containerization became cheap and ubiquitous. Thus the holy build box approach became viable to the average developer.

Other comparable systems

We have heard that the Meson build system also allows compiling cross-distribution Linux binaries. Meson is more fully-featured than Holy Build Box in that it tries to abstract away library and dependency management.

One of the most interesting features in Meson is that it automatically generates a dependency manifest when you use it to create statically linked binaries. This manifest allows you to find out which library versions a binary is linked to, which in turn allows you to automatically scan binaries for security vulnerabilities. Holy Build Box may follow this approach some time in the future.

More Repositories

1

baseimage-docker

A minimal Ubuntu base image modified for Docker-friendliness
Shell
8,943
star
2

passenger

A fast and robust web server and application server for Ruby, Python and Node.js
C++
4,983
star
3

passenger-docker

Docker base images for Ruby, Python, Node.js and Meteor web apps
Shell
2,764
star
4

traveling-ruby

Self-contained Ruby binaries that can run on any Linux distribution and any macOS machine.
Shell
2,097
star
5

juvia

A commenting server similar to Disqus and IntenseDebate.
Ruby
1,027
star
6

open-vagrant-boxes

Docker-compatible Vagrant base boxes
Shell
518
star
7

passenger-ruby-heroku-demo

Demonstrates running a Ruby app on Heroku with Phusion Passenger
Ruby
280
star
8

node-sha3

SHA3 for JavaScript - The Keccak family of hash algorithms
JavaScript
141
star
9

nginx

Git mirror of the Nginx SVN repository, automatically updated 2 times a day.
C
112
star
10

digest-sha3-ruby

SHA-3 (Keccak) extension for Ruby
C
65
star
11

passenger-ruby-websocket-demo

Demonstration of WebSockets on Phusion Passenger
CSS
63
star
12

phusion-server-tools

Set of server administration tools that we use at Phusion.
Ruby
60
star
13

passenger_library

Phusion Passenger documentation
HTML
48
star
14

passenger-nodejs-websocket-demo

Phusion Passenger: Node.js WebSocket demo
CSS
36
star
15

passenger-ruby-server-sent-events-demo

Phusion Passenger: HTML5 Server Side Events demo (Ruby version)
Ruby
33
star
16

apachai-hopachai

Travis-like continuous integration (CI) system built on Docker
Ruby
27
star
17

eurovat

European Union VAT number utilities
Ruby
25
star
18

nginx-modsecurity-ubuntu

Ubuntu package for modsecurity-nginx
Makefile
23
star
19

frontapp

Ruby client to work with Frontapp API
Ruby
23
star
20

action-cable-demo

A project to demonstrate ActionCable
Ruby
20
star
21

passenger_apt_automation

Tools for automatically building a Debian APT repository for Phusion Passenger
C
20
star
22

passenger-python-flask-demo

Passenger: Flask example app
HTML
20
star
23

passenger_rpm_automation

Phusion Passenger RPM packaging automation
HTML
19
star
24

passenger_autobuilder

Phusion Passenger binary building automation infrastructure. Superceded by https://github.com/phusion/passenger_binary_build_automation
Shell
17
star
25

passenger-ruby-sinatra-demo

Passenger: Sinatra example app
HTML
17
star
26

passenger-ruby-rails-demo

Passenger: Ruby on Rails example app
Ruby
12
star
27

passenger_status_service

[DEPRECATED] Make Passenger status reports work on Heroku
Ruby
11
star
28

netdata-ubuntu-16.04

Ubuntu 16.04 packages for netdata
JavaScript
9
star
29

support_central

Manage multiple user support channels with ease
Ruby
9
star
30

unicorn

Ruby application server. Includes Phusion extensions. Automatically synchronized with Eric Wong's repo every 6 hours (see the eric_master branch).
Ruby
7
star
31

SheetsAPI

A simple API for writing to Google Sheets
Ruby
5
star
32

traveling-ruby-gems-demo

Traveling Ruby tutorial 2: gem dependencies
Ruby
5
star
33

cxxcodebuilder

Generate C/C++ code with a Builder-style DSL
Ruby
5
star
34

phusion-mvc

A frontend MVC framework with Polymer
JavaScript
4
star
35

onepush

Simple web app server setup and deployment
Ruby
4
star
36

traveling-ruby-hello-demo

Traveling Ruby tutorial 1: hello world
Ruby
3
star
37

ruby-reaper

A Ruby script that can run as PID1 and reaps orphan and zombie processes
Ruby
3
star
38

passenger_binary_build_automation

System for building portable binaries for Phusion Passenger
Shell
3
star
39

passenger-ruby-faye-websocket-demo

Demonstrates WebSockets on Phusion Passenger through the faye-websocket gem
CSS
3
star
40

homebrew-passenger-enterprise

Passenger Enterprise Homebrew formula
Ruby
3
star
41

frontapp-spam-filter

Implements a spam filter for Front through webhooks and a third party service
Ruby
3
star
42

brow-route.js

A simple hash based router for modern web applications
CoffeeScript
2
star
43

phusion-docker-classic-linux

Docker images for 32-bit Ubuntu 10.04 and CentOS 5
Shell
2
star
44

passenger-docker-redhat

Docker images for running Ruby, Python, Node.js and Meteor web apps with Passenger
Python
2
star
45

rails-cve-2012-5664-test

Demo app showing how the Rails CVE-2013-5664 vulnerability works.
Ruby
2
star
46

union_station_hooks_rails

Union Station Ruby on Rails hooks
Ruby
2
star
47

traveling-ruby-native-extensions-demo

Traveling Ruby tutorial 2: native extensions
Ruby
2
star
48

traveling-ruby-windows-demo

Traveling Ruby tutorial 4: creating packages for Windows
Ruby
1
star
49

phusion-spa

A Single Page App view switching system for Polymer
HTML
1
star
50

laposta

Ruby client for Laposta API
Ruby
1
star
51

passenger-ci-test

A mock Passenger repository for testing our CI scripts
C++
1
star
52

actioncable-slow-client

A project to test ActionCable with slow clients
Ruby
1
star
53

bottleneck_benchmark

Rails project for benchmarking application servers for applications with CPU or IO bottlenecks.
Ruby
1
star
54

passenger-nodejs-connect-demo

Passenger + Node.js/io.js + Connect.js example app
JavaScript
1
star
55

rails_wizard_support

Support library for writing wizard models in Rails.
Ruby
1
star
56

zangetsu

A NoSQL database written in Node.js
JavaScript
1
star
57

supportbee_sla_enforcer

SLA enforcement script for Supportbee
Ruby
1
star
58

passenger_homebrew_automation

Phusion Passenger Homebrew formula release automation
Ruby
1
star