Usrmerge implementation¶
Usrmerge is a collection of methods for combining the /usr
directories in the Linux
filesystem hierarchy. Because there’s no single cross-compatible solution recommended
by the Filesystem Hierarchy Standard,
different Linux distributions have provided different solutions to this problem over
time.
Rocks can contain Ubuntu as a baseline system, so Rockcraft must also contend with usrmerge. This page explains how its usrmerge implementation works.
Merge conflicts¶
For a long period in Linux filesystem design, executables were placed either in the
/bin
or /usr/bin
directories at the discretion of the developer. However, over
time, a consensus developed that the two directories should be combined, for simplicity
and a compatibility between different Linux distributions. Across many distributions,
this has most commonly resulted in /bin
becoming a symbolic link to /usr/bin
.
For Ubuntu, the first long-term release with this behavior was Ubuntu 24.04 LTS.
Conflicts occur when different pieces of software inside a Linux system disagree about
what type of filesystem object /bin
should be. Plugins in Rockcraft place their
final files into /bin
. They create /bin
as a regular directory if it does not
exist either as a directory or a link, but other packages may expect /bin
to be a
symbolic link to /usr/bin
, resulting in a file conflict.
As an example, consider the following rock project snippet:
parts:
my-go-project:
plugin: go
source: .
my-dependencies:
plugin: nil
stage-packages:
- base-files
This rock succeeds when building with the ubuntu@22.04
base, creating a single
/bin/my-go-project
executable when /bin
is a directory. However, building the
same rock with ubuntu@24.04
will fail, as this new version of base-files
creates
/bin
as a symbolic link to /usr/bin
. Then, my-go-project
stages
/bin/my-go-project
. Since /bin
can’t be both a regular directory and a symbolic
link, a conflict arises.
Merging /usr
directories in rocks¶
When designing a usrmerge solution for rocks, the priority was to fix the problem for future rocks. The solution had to avoid any assumptions about the part’s existing file structure. In addition, while the merge should be automatic for those who don’t wish to worry about it, it had to also allow users to opt in or out of the behavior in order to support older rocks.
To serve these goals, at the start of the pull step of the lifecycle, Rockcraft ensures
the install directory of a part is pre-populated with the appropriate directories and
symbolic links. This means that inside a part, bin
is always linked to usr/bin
,
adhering to the newer standard and disambiguating the files before plugins have a chance
to create a regular bin
directory. While this does not impact the final artifact, it
does impact what files are available during the build process.
Plugin syntax and compatibility¶
The usrmerge implementation is automatically enabled when building with the
ubuntu@25.10
base and higher. It can be opted into for bases lower than
ubuntu@25.10
with the enable-usrmerge
build attribute, or disabled on newer
bases with disable-usrmerge
.
All plugins are affected by these changes, except for the Dump plugin and Nil plugin. These plugins serve a different niche than language plugins, providing a means to customize the process. Due to this, they leave it up to the project to properly organize and stage their outputs – it didn’t make sense to enforce a filesystem structure onto them.
With usrmerge, any override-build scripts are subject to breaking. Since these are
entirely free-form Bash scripts, it’s plausible that some are written with the
assumption that /bin
will be a plain directory. To resolve this potential conflict,
the following build attributes are available:
Key |
Effect |
---|---|
|
When building on |
|
When building on |