summerofcode2019projects:portsseparatedbuild

This is an old revision of the document!


Separation of Ports Build Process from Local Installation

This project aims to provide the capability of the FreeBSD ports infrastructure to safely and cleanly build ports and all their dependencies without superuser privileges, jails, or touching the installed system in anyway, in the interest of improving the safety, reliability, and repeatability of ports building without the administrative and resource overhead of a separated build host or jail.

This will bring the building capability of ports tree in line with what is already possible for FreeBSD base system: separate build vs. install workflow.

Currently this level of separation can only be accomplished in practice through chroot or Jail. This project will eliminate the need for cooperation of the root user since /usr/local will not need to be touched. To enable this, file accesses will be redirected to a location controlled by the ports build process through use of a userspace library to intercept file accesses.

This implementation takes the possibility of cross-building of ports into consideration as a long-term goal (far beyond end of GSoC due to the significant challenges and history of ports not taking this into consideration).

Where possible, the need for the userspace file interception hack should be eliminated, by switching to use of build tools supporting sysroot (this is analogous to desirability of sysroot-capable compiler vs. user-mode emulation for cross-arch compilation). The interception tool serves to cover otherwise uncooperative software.

  • File path redirection library, capable of emulating chroot behavior on any dynamically-linked executable (BSD replacement for “fakechroot”)
  • bsd.port.mk coordinates usage of temporary dependency location
  • Most ports are buildable without any interaction with real ${PREFIX}
  • Packages built by modified process are identical to packages build by existing ports framework

Running the entire ports framework in a chroot (as is trivially possible) defeats the purpose of the project, since it only moves the problem of isolating each port's build environment from a physical host to a virtual one: Ports framework itself, not just a blanket chroot created by system administrator, should configure the build-environment of each port.

The commands needed for the ports infrastructure are logically separated as follows:

  • Ports-framework commands, such as dependency calculation, fetching(*), patching(*), and packaging
    • (*) fetching and patching may require tools from ports in unusual cases
  • Port-building commands, such as configure, make, (staged)install, tests

However, the existing implementation of the ports framework does not make this a clear distinction, since no such distinction has been needed for the existing capabilities of the ports framework. The distinction becomes important when the building processes of ports must occur in a specially prepared environment managed by the ports framework itself. Places where setup of this environment is needed roughly follows existing usage of ${CONFIGURE_ENV} / ${MAKE_ENV} / etc.

  • Ports are built using PORTS_SEPARATED_BUILD=1 set (otherwise normal ports behavior is left alone as the default).
  • Port building is started from unprivileged user. All compilation work is run as this user.
    • Superuser is requested for configuring and switching into chroot (switches back to user after entering chroot). This will be obviated by integration of userspace file redirection tool.
  • Ports built as dependencies are installed to a working directory, not system-wide.
  • Dependency resolution is patched to use this working directory.
  • All port-building commands (configure scripts, compilers, interpreters) run under file redirection to see dependency install area instead of local system.
    • Current implementation of file redirection: chroot.
  • Anything using standard configure/make procedure
  • Builds using Autoreconf; requires patch to Mk/Uses/autoreconf.mk
  • Builds using Cmake; requires patch to Mk/Uses/cmake.mk
  • USES=perl; requires patch to Mk/Uses/perl5.mk
  • USES=python; requires patch to Mk/Uses/python.mk
  • Anything using custom targets in port's Makefile (requires patch for each port)
  • Familiarized myself with the port dependency mechanisms in /usr/ports/Mk/Scripts.
  • Hacked on bsd.port.mk to check assumptions and to get an idea of what additions will be needed.
  • Studied /usr/src/lib/libc to understand chain of userspace calls between C API and system call. Implemented proof-of-concept redirection library intercepting open(…).
  • Continued to work on the file access interception library. It is working well enough to redirect file accesses from shell and basic tools: sh, cat, ls - more thorough testing will be needed.
  • Modified bsd.port.mk to behave as follows:
    • All built dependencies of a port are installed to ${PORTBLDROOT} (=${PORTSDIR}/build on my test system).
    • Ports resolve dependencies to ${PORTBLDROOT} instead of to local system.
    • All port-building operations (configure, make, make install, etc.) are run in a chroot, in which ${LOCALBASE} is mapped to ${PORTBLDROOT}${LOCALBASE} and base system is mapped as-is.
  • Added hooks to several Mk/Uses/* and ports to allow switch to chroot where appropriate (far from complete).
  • Successfully compiled handful of ports (including C libraries, GNU build tools, perl modules, and python modules) under this modified system.
  • Next stage:
    • Replace the chroot with an equivalent solution in userspace (filesystem namespace redirection), to eliminate requirement of superuser intervention.
  • Switched bsd.port.mk from using a chroot for namespace manipulation to using the userspace namespace tool.
  • Enabled namespace tool to read path mappings from environment, supplied by bsd.port.mk
  • Re-ran port builds. Several problems which had not occurred when using chroot became introduced.
  • Studied interactions between executables, namespace tool, dynamic linker, and standard library to understand the cases in which file accesses fail to be intercepted.
  • Next stage:
    • Research, design, implement, and test appropriate solutions for the problems encountered with userspace file access interception.
Week Task Progress
05/27 - 05/31 Study dependency resolution mechanisms in Mk/bsd.port.mk, Mk/Scripts/*, what works, what doesn’t, in context of a temporary install location. Familiarized with port dependency mechanisms in /usr/ports/Mk/Scripts. Studied /usr/src/lib/libc to understand chain of userspace calls between C API and system call. Implemented proof-of-concept redirection library intercepting open(…).
06/03 - 06/07 Implement file path redirection library and test against common tools File redirection library is working for basic file operations performed by common shell utilities.
06/10 - 06/14 Modify bsd.port.mk (and related) to utilize install location and redirection lib Working branch of freebsd-ports utilizes a virtual install location, and some ports are able to build using dependencies installed to this location. See above.
06/17 - 06/21 Demonstrate successful building of a port with dependencies Ports with dependencies function under chroot, not under userspace file tool.
06/24 - 06/28 Document and present findings
07/01 - 07/12 Identify ports using statically linked build tools. Add option for building such tools to include file path redirection support.
07/15 - 07/26 Build a larger number of ports. See what breaks and why.
07/22 - 07/26 Document findings and present progress
07/29 - 08/04 Fix problems which prevent some ports from building.
08/11 - 08/23 Thoroughly test process. Document what can’t be fixed and why.
08/19 - 08/23 Thoroughly document all added components and present summary of compatibility.
  • summerofcode2019projects/portsseparatedbuild.1561394793.txt.gz
  • Last modified: 2019/06/24 16:46
  • by TheronTarigo