FreeBSD support
Here is the patch I used to get a simple import
element work on FreeBSD:
https://gitlab.com/snippets/1692852
The only tested commands are bst build
and bst shell
. It is not ready to be merged and it is only used to show what changes may be required to get BuildStream work on FreeBSD.
diff --git a/buildstream/sandbox/_mounter.py b/buildstream/sandbox/_mounter.py
index 3f82993..f48a42c 100644
--- a/buildstream/sandbox/_mounter.py
+++ b/buildstream/sandbox/_mounter.py
@@ -60,7 +60,11 @@ class Mounter(object):
@classmethod
def _umount(cls, path, stdout=sys.stdout, stderr=sys.stderr):
- cmd = [utils.get_host_tool('umount'), '-R', path]
+ if sys.platform.startswith('linux'):
+ cmd = [utils.get_host_tool('umount'), '-R', path]
+ else:
+ cmd = [utils.get_host_tool('umount'), path]
+
status, _ = utils._call(
cmd,
terminate=True,
@@ -131,15 +135,24 @@ class Mounter(object):
def kill_proc():
cls._umount(dest, stdout, stderr)
- kwargs['rbind'] = True
+ mount_type = None
+
+ if sys.platform.startswith('linux'):
+ kwargs['rbind'] = True
+ elif sys.platform.startswith('freebsd'):
+ mount_type = 'nullfs'
+ else:
+ assert False, 'Please implement bind_mount function for your OS'
+
options = ','.join([key for key, val in kwargs.items() if val])
- path = cls._mount(dest, src, None, stdout, stderr, options)
+ path = cls._mount(dest, src, mount_type, stdout, stderr, options)
with _signals.terminator(kill_proc):
# Make the rbind a slave to avoid unmounting vital devices in
# /proc
- cls._mount(dest, flags=['--make-rslave'])
+ if sys.platform.startswith('linux'):
+ cls._mount(dest, flags=['--make-rslave'])
yield path
cls._umount(dest, stdout, stderr)
diff --git a/buildstream/sandbox/_sandboxchroot.py b/buildstream/sandbox/_sandboxchroot.py
index 0a60436..3f15e9f 100644
--- a/buildstream/sandbox/_sandboxchroot.py
+++ b/buildstream/sandbox/_sandboxchroot.py
@@ -141,7 +141,7 @@ class SandboxChroot(Sandbox):
# If you try to put gtk dialogs here Tristan (either)
# will personally scald you
preexec_fn=lambda: (os.chroot(rootfs), os.chdir(cwd)),
- start_new_session=flags & SandboxFlags.INTERACTIVE
+ start_new_session=False
)
# Wait for the child process to finish, ensuring that
@@ -260,16 +260,28 @@ class SandboxChroot(Sandbox):
with Mounter.bind_mount(mount_point, src=src, stdout=stdout, stderr=stderr, **kwargs):
yield
+ @contextmanager
+ def mount_fs(src, point, mount_type, **kwargs):
+ mount_point = os.path.join(rootfs, point.lstrip(os.sep))
+ os.makedirs(mount_point, exist_ok=True)
+
+ with Mounter.mount(mount_point, src=src, stdout=stdout, stderr=stderr, mount_type=mount_type, **kwargs):
+ yield
+
with ExitStack() as stack:
stack.enter_context(self.mount_map.mounted(self))
stack.enter_context(mount_point('/'))
if flags & SandboxFlags.INTERACTIVE:
- stack.enter_context(mount_src('/dev'))
+ if sys.platform.startswith('freebsd'):
+ stack.enter_context(mount_fs('devfs', '/dev', 'devfs'))
+ else:
+ stack.enter_context(mount_src('/dev'))
- stack.enter_context(mount_src('/tmp'))
- stack.enter_context(mount_src('/proc'))
+ if not sys.platform.startswith('freebsd') and \
+ not sys.platform.startswith('openbsd'):
+ stack.enter_context(mount_src('/proc'))
for mark in self._get_marked_directories():
stack.enter_context(mount_point(mark['directory']))
Reasons for the patch:
-
umount
on FreeBSD doesn't have-R
option. I could not find a equivalent of it. -
mount
on FreeBSD doesn't haverbind
mount option. It does have a equivalent ofbind
on Linux callednullfs
, which can be used by runningmount_nullfs
.mount -t nullfs
runsmount_nullfs
to do the work. Other *BSD seem to call itmount_null
instead ofmount_nullfs
. -
start_new_session
is set to False because relinquishing the controlling terminal causessh
to show 'sh: can't access tty; job control turned off' when it fails to open/dev/tty
. - Mounting a new
devfs
fixes 'sh: can't access tty; job control turned off' caused bytcgetpgrp
, which fails with 'Inappropriate ioctl for device' when/dev
is bind-mounted from the host. - Bind-mounting of
/tmp
is temporarily removed to avoid serious breakage being done to the host system when the sandbox code raises an exception. It seems that an exception in the sandbox code can triggercleanup_tempdir
function inbuildstream/utils.py
, which removes everything in/tmp
on the host because of bind-mounting. This breaks a lot of software, such as Xorg, GNU screen, tmux on the host because they rely on socket files put in/tmp
. - Bind-mounting of
/proc
is made optional becauseprocfs
is deprecated on FreeBSD. Applications relying on/proc
being mounted should be updated to use thesysctl
interface. I also added OpenBSD to the check because OpenBSD has removedprocfs
support from its kernel.
I found that buildstream/sandbox/_sandboxchroot.py
uses remount
. The FreeBSD equivalent of remount
is update
, but it doesn't seems to work on all file systems. mount -o update,ro
works on UFS, but I cannot get it work on ZFS, nullfs, tmpfs. I haven't checked whether this can become a problem because my simple test case doesn't reach this line of code.
I also found there is a comment in buildstream/sandbox/_sandboxchroot.py
says that not copying /etc/resolv.conf
effectively disables network access. However, tt is interesting to see that command such as ftp ftp.freebsd.org
does work inside bst shell
because I have a caching DNS resolver running on localhost. I think the best way to disable network access may be using a jail instead of a chroot on FreeBSD. This requires writing new code to support FreeBSD jail.
Since BuildStream is going to replace JHBuild, I hope we can support the following features in BuildStream. I haven't checked whether they are already possible with current BuildStream configuration:
-
Platform-dependent default values for options. The key feature which enables us to run JHBuild on FreeBSD is
<if>
elements in JHBuild modulesets. JHBuild has different default condition sets for each supported operating system. For example, The default on Linux is['evdev', 'gnu-elf', 'linux', 'systemd', 'udev', 'wayland', 'x11']
and the default on FreeBSD is['bsd', 'freebsd', 'gmake', 'gnu-elf', 'x11']
. I hope we can have similar feature in BuildStream, so we don't have to ask users on FreeBSD to manually set a lot of options on the command line or in the configuration file. -
Is it possible to override the branch or tag used by an element in user configuration file? We have
branches
in jhbuildrc. It is useful when upstream developer introduces build breakage on FreeBSD which is hard to fix. I knowbst track
writes the commit used by an element back to the element file, but the output ofgit diff
is going to be hard to read if I track more than 200 elements. -
Is it possible to override arguments and environment variables used by an element in user configuration file? We have
module_autogenargs
,module_cmakeargs
,module_mesonargs
,module_extra_env
in jhbuildrc. They are useful to workaround build problems and enable non-default features. For example, we add-Wno-error=format-nonliteral
toCFLAGS
of many modules because fixing all format string errors will take a lof of time. I also enable GTK-Doc build for all modules so I can find documentation I need simply by running devhelp inside the JHBuild prefix. This also help us catch GTK-Doc-related problems early. -
Unlike most GNU/Linux distributions which use only one prefix, namely
/usr
, FreeBSD has at least two prefixes:/usr
is the prefix reserved for the base system. All packages, which are considered third-party software, should be installed in a different prefix. The default prefix for packages is/usr/local
and it is used by all binary packages provided by FreeBSD project. If users want to use different prefixes, they can build their own packages from FreeBSD ports. Hard-coding/usr/local
is considered a bug in FreeBSD ports. The system compiler and linker doesn't search the prefix used by packages for headers and libraries by default, andCPPFLAGS
andLDFLAGS
are used to specify the path for headers and libraries, respectively. JHBuild hasextra_prefixes
in jhbuildrc which partly solve the problem. The default jhbuildrc file adds/usr/local
toextra_prefixes
whensys.path
includes paths starting with/usr/local/lib
, and JHBuild can setup many environment variables forextra_prefixes
, includingC_INCLUDE_PATH
,CPLUS_INCLUDE_PATH
,LDFLAGS
. However, we cannot accessextra_prefixes
in JHBuild modulesets so we still hard-codes/usr/local
for FreeBSD in modulesets. I hope we can support both two-prefix and three-prefix setups in BuildStream. Two-prefix is similar to one-prefix used on GNU/Linux, which is used to have better system integration and make it possible to generate VM images to test system components. Three-prefix is a JHBuild-like setup where all GNOME modules are installed into a separate prefix. It is more likely to go wrong, but it is still useful for testing and it should have less overlapping files. -
JHBuild remove libtool .la files by default, but BuildStream keeps them. Is there any reason to keep them by default? I think no GNOME modules need them and projects depending on libtool .la files because of libltdl should explicitly set an option to keep it. libtool .la files are not required for dynamic linking on ELF systems and having them installed on the system has caused many build failure because of wrong -L order on FreeBSD. Most GNU/Linux distributions also remove them.
i currently use jhbuild run gnome-session
as the primary way to test GNOME on FreeBSD. It is also the desktop environment I use on FreeBSD most of the time. I don't know whether it is a valid use cause of JHBuild and I don't expect it to be supported in BuildStream, but I think I may be able to do it with bst checkout
in a three-prefix setup mentioned above.
In fact, JHBuild never works out of the box on FreeBSD because there are always outstanding issues preventing the build from finishing successfully, but having modulesets maintained in an official GNOME repository does make the situation much better. The list of issues is currently maintained on https://wiki.gnome.org/Projects/Jhbuild/FreeBSD. I don't expect BuildStream to reduce the number of build breakage on FreeBSD and I think we will still have to maintain a list of issues and workarounds after switching to BuildStream. The goal of FreeBSD support in BuildStream is the same as FreeBSD support in JHBuild. It enables us to catch problems very early and make debugging much easier.