Add a Meson build system
This allows bwrap to be built as a subproject in larger Meson projects. When built as a subproject, we install into the --libexecdir and require a program prefix to be specified: for example, Flatpak would use program_prefix=flatpak- to get /usr/libexec/flatpak-bwrap. Verified to be backwards-compatible as far as Meson 0.49.0 (Debian 9 backports). Loosely based on previous work by Jussi Pakkanen (see #133). Differences between the Autotools and Meson builds: The Meson build requires a version of libcap that has pkg-config metadata (introduced in libcap 2.23, in 2013). The Meson build has no equivalent of --with-priv-mode=setuid. On distributions like Debian <= 10 and RHEL <= 7 that require a setuid bwrap executable, the sysadmin or distribution packaging will need to set the correct permissions on the bwrap executable; Debian already did this via packaging rather than the upstream build system. The Meson build supports being used as a subproject, and there is CI for this. It automatically disables shell completions and man pages, moves the bubblewrap executable to ${libexecdir}, and renames the bubblewrap executable according to a program_prefix option that the caller must specify (for example, Flatpak would use -Dprogram_prefix=flatpak- to get /usr/libexec/flatpak-bwrap). See the tests/use-as-subproject/ directory for an example. Signed-off-by: Simon McVittie <smcv@collabora.com>
This commit is contained in:
67
.github/workflows/check.yml
vendored
67
.github/workflows/check.yml
vendored
@@ -10,7 +10,7 @@ on:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
check:
|
check:
|
||||||
name: Build with gcc and test
|
name: Build with Autotools and gcc, and test
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Check out
|
- name: Check out
|
||||||
@@ -69,6 +69,71 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
make -C _build -j $(getconf _NPROCESSORS_ONLN) distcheck VERBOSE=1 BWRAP_MUST_WORK=1
|
make -C _build -j $(getconf _NPROCESSORS_ONLN) distcheck VERBOSE=1 BWRAP_MUST_WORK=1
|
||||||
|
|
||||||
|
meson:
|
||||||
|
name: Build with Meson and gcc, and test
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Check out
|
||||||
|
uses: actions/checkout@v1
|
||||||
|
- name: Install build-dependencies
|
||||||
|
run: sudo ./ci/builddeps.sh
|
||||||
|
- name: Create logs dir
|
||||||
|
run: mkdir test-logs
|
||||||
|
- name: setup
|
||||||
|
run: |
|
||||||
|
meson _build
|
||||||
|
env:
|
||||||
|
CFLAGS: >-
|
||||||
|
-O2
|
||||||
|
-Wp,-D_FORTIFY_SOURCE=2
|
||||||
|
-fsanitize=address
|
||||||
|
-fsanitize=undefined
|
||||||
|
- name: compile
|
||||||
|
run: ninja -C _build -v
|
||||||
|
- name: smoke-test
|
||||||
|
run: |
|
||||||
|
set -x
|
||||||
|
./_build/bwrap --bind / / --tmpfs /tmp true
|
||||||
|
env:
|
||||||
|
ASAN_OPTIONS: detect_leaks=0
|
||||||
|
- name: test
|
||||||
|
run: |
|
||||||
|
BWRAP_MUST_WORK=1 meson test -C _build
|
||||||
|
env:
|
||||||
|
ASAN_OPTIONS: detect_leaks=0
|
||||||
|
- name: Collect overall test logs on failure
|
||||||
|
if: failure()
|
||||||
|
run: mv _build/meson-logs/testlog.txt test-logs/ || true
|
||||||
|
- name: install
|
||||||
|
run: |
|
||||||
|
DESTDIR="$(pwd)/DESTDIR" meson install -C _build
|
||||||
|
( cd DESTDIR && find -ls )
|
||||||
|
- name: dist
|
||||||
|
run: |
|
||||||
|
BWRAP_MUST_WORK=1 meson dist -C _build
|
||||||
|
- name: Collect dist test logs on failure
|
||||||
|
if: failure()
|
||||||
|
run: mv _build/meson-private/dist-build/meson-logs/testlog.txt test-logs/disttestlog.txt || true
|
||||||
|
- name: use as subproject
|
||||||
|
run: |
|
||||||
|
mkdir tests/use-as-subproject/subprojects
|
||||||
|
tar -C tests/use-as-subproject/subprojects -xf _build/meson-dist/bubblewrap-*.tar.xz
|
||||||
|
mv tests/use-as-subproject/subprojects/bubblewrap-* tests/use-as-subproject/subprojects/bubblewrap
|
||||||
|
( cd tests/use-as-subproject && meson _build )
|
||||||
|
ninja -C tests/use-as-subproject/_build -v
|
||||||
|
meson test -C tests/use-as-subproject/_build
|
||||||
|
DESTDIR="$(pwd)/DESTDIR-as-subproject" meson install -C tests/use-as-subproject/_build
|
||||||
|
( cd DESTDIR-as-subproject && find -ls )
|
||||||
|
test -x DESTDIR-as-subproject/usr/local/libexec/not-flatpak-bwrap
|
||||||
|
test ! -e DESTDIR-as-subproject/usr/local/bin/bwrap
|
||||||
|
test ! -e DESTDIR-as-subproject/usr/local/libexec/bwrap
|
||||||
|
- name: Upload test logs
|
||||||
|
uses: actions/upload-artifact@v1
|
||||||
|
if: failure() || cancelled()
|
||||||
|
with:
|
||||||
|
name: test logs
|
||||||
|
path: test-logs
|
||||||
|
|
||||||
clang:
|
clang:
|
||||||
name: Build with clang and analyze
|
name: Build with clang and analyze
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
10
Makefile.am
10
Makefile.am
@@ -5,11 +5,21 @@ EXTRA_DIST = \
|
|||||||
.editorconfig \
|
.editorconfig \
|
||||||
README.md \
|
README.md \
|
||||||
autogen.sh \
|
autogen.sh \
|
||||||
|
completions/bash/meson.build \
|
||||||
|
completions/meson.build \
|
||||||
|
completions/zsh/meson.build \
|
||||||
demos/bubblewrap-shell.sh \
|
demos/bubblewrap-shell.sh \
|
||||||
demos/flatpak-run.sh \
|
demos/flatpak-run.sh \
|
||||||
demos/flatpak.bpf \
|
demos/flatpak.bpf \
|
||||||
demos/userns-block-fd.py \
|
demos/userns-block-fd.py \
|
||||||
|
meson.build \
|
||||||
|
meson_options.txt \
|
||||||
packaging/bubblewrap.spec \
|
packaging/bubblewrap.spec \
|
||||||
|
tests/meson.build \
|
||||||
|
tests/use-as-subproject/README \
|
||||||
|
tests/use-as-subproject/config.h \
|
||||||
|
tests/use-as-subproject/dummy-config.h.in \
|
||||||
|
tests/use-as-subproject/meson.build \
|
||||||
uncrustify.cfg \
|
uncrustify.cfg \
|
||||||
uncrustify.sh \
|
uncrustify.sh \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
@@ -64,6 +64,7 @@ if dpkg-vendor --derives-from Debian; then
|
|||||||
libcap-dev \
|
libcap-dev \
|
||||||
libselinux1-dev \
|
libselinux1-dev \
|
||||||
libtool \
|
libtool \
|
||||||
|
meson \
|
||||||
pkg-config \
|
pkg-config \
|
||||||
python3 \
|
python3 \
|
||||||
xsltproc \
|
xsltproc \
|
||||||
@@ -92,6 +93,7 @@ if command -v yum; then
|
|||||||
libubsan \
|
libubsan \
|
||||||
libxslt \
|
libxslt \
|
||||||
make \
|
make \
|
||||||
|
meson \
|
||||||
redhat-rpm-config \
|
redhat-rpm-config \
|
||||||
rsync \
|
rsync \
|
||||||
${NULL+}
|
${NULL+}
|
||||||
|
37
completions/bash/meson.build
Normal file
37
completions/bash/meson.build
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
bash_completion_dir = get_option('bash_completion_dir')
|
||||||
|
|
||||||
|
if bash_completion_dir == ''
|
||||||
|
bash_completion = dependency(
|
||||||
|
'bash-completion',
|
||||||
|
version : '>=2.0',
|
||||||
|
required : false,
|
||||||
|
)
|
||||||
|
|
||||||
|
if bash_completion.found()
|
||||||
|
if meson.version().version_compare('>=0.51.0')
|
||||||
|
bash_completion_dir = bash_completion.get_variable(
|
||||||
|
default_value: '',
|
||||||
|
pkgconfig: 'completionsdir',
|
||||||
|
pkgconfig_define: [
|
||||||
|
'prefix', get_option('prefix'),
|
||||||
|
'datadir', get_option('prefix') / get_option('datadir'),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
else
|
||||||
|
bash_completion_dir = bash_completion.get_pkgconfig_variable(
|
||||||
|
'completionsdir',
|
||||||
|
default: '',
|
||||||
|
define_variable: [
|
||||||
|
'prefix', get_option('prefix'),
|
||||||
|
'datadir', get_option('prefix') / get_option('datadir'),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
if bash_completion_dir == ''
|
||||||
|
bash_completion_dir = get_option('datadir') / 'bash-completion' / 'completions'
|
||||||
|
endif
|
||||||
|
|
||||||
|
install_data('bwrap', install_dir : bash_completion_dir)
|
7
completions/meson.build
Normal file
7
completions/meson.build
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
if get_option('bash_completion').enabled()
|
||||||
|
subdir('bash')
|
||||||
|
endif
|
||||||
|
|
||||||
|
if get_option('zsh_completion').enabled()
|
||||||
|
subdir('zsh')
|
||||||
|
endif
|
7
completions/zsh/meson.build
Normal file
7
completions/zsh/meson.build
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
zsh_completion_dir = get_option('zsh_completion_dir')
|
||||||
|
|
||||||
|
if zsh_completion_dir == ''
|
||||||
|
zsh_completion_dir = get_option('datadir') / 'zsh' / 'site-functions'
|
||||||
|
endif
|
||||||
|
|
||||||
|
install_data('_bwrap', install_dir : zsh_completion_dir)
|
147
meson.build
Normal file
147
meson.build
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
project(
|
||||||
|
'bubblewrap',
|
||||||
|
'c',
|
||||||
|
version : '0.5.0',
|
||||||
|
meson_version : '>=0.49.0',
|
||||||
|
default_options : [
|
||||||
|
'warning_level=2',
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
cc = meson.get_compiler('c')
|
||||||
|
add_project_arguments('-D_GNU_SOURCE', language : 'c')
|
||||||
|
|
||||||
|
# Keep this in sync with ostree, except remove -Wall (part of Meson
|
||||||
|
# warning_level 2) and -Werror=declaration-after-statement
|
||||||
|
add_project_arguments(
|
||||||
|
cc.get_supported_arguments([
|
||||||
|
'-Werror=shadow',
|
||||||
|
'-Werror=empty-body',
|
||||||
|
'-Werror=strict-prototypes',
|
||||||
|
'-Werror=missing-prototypes',
|
||||||
|
'-Werror=implicit-function-declaration',
|
||||||
|
'-Werror=pointer-arith',
|
||||||
|
'-Werror=init-self',
|
||||||
|
'-Werror=missing-declarations',
|
||||||
|
'-Werror=return-type',
|
||||||
|
'-Werror=overflow',
|
||||||
|
'-Werror=int-conversion',
|
||||||
|
'-Werror=parenthesis',
|
||||||
|
'-Werror=incompatible-pointer-types',
|
||||||
|
'-Werror=misleading-indentation',
|
||||||
|
'-Werror=missing-include-dirs',
|
||||||
|
'-Werror=aggregate-return',
|
||||||
|
|
||||||
|
# Extra warnings specific to bubblewrap
|
||||||
|
'-Werror=switch-default',
|
||||||
|
'-Wswitch-enum',
|
||||||
|
|
||||||
|
# Meson warning_level=2 would do this, but we are not fully
|
||||||
|
# signedness-safe yet
|
||||||
|
'-Wno-sign-compare',
|
||||||
|
'-Wno-error=sign-compare',
|
||||||
|
|
||||||
|
# Deliberately not warning about these, ability to zero-initialize
|
||||||
|
# a struct is a feature
|
||||||
|
'-Wno-missing-field-initializers',
|
||||||
|
'-Wno-error=missing-field-initializers',
|
||||||
|
]),
|
||||||
|
language : 'c',
|
||||||
|
)
|
||||||
|
|
||||||
|
if (
|
||||||
|
cc.has_argument('-Werror=format=2')
|
||||||
|
and cc.has_argument('-Werror=format-security')
|
||||||
|
and cc.has_argument('-Werror=format-nonliteral')
|
||||||
|
)
|
||||||
|
add_project_arguments([
|
||||||
|
'-Werror=format=2',
|
||||||
|
'-Werror=format-security',
|
||||||
|
'-Werror=format-nonliteral',
|
||||||
|
], language : 'c')
|
||||||
|
endif
|
||||||
|
|
||||||
|
sh = find_program('sh', required : true)
|
||||||
|
bash = find_program('bash', required : false)
|
||||||
|
|
||||||
|
libcap_dep = dependency('libcap', required : true)
|
||||||
|
|
||||||
|
selinux_dep = dependency(
|
||||||
|
'libselinux',
|
||||||
|
version : '>=2.1.9',
|
||||||
|
# if disabled, Meson will behave as though libselinux was not found
|
||||||
|
required : get_option('selinux'),
|
||||||
|
)
|
||||||
|
|
||||||
|
cdata = configuration_data()
|
||||||
|
cdata.set_quoted(
|
||||||
|
'PACKAGE_STRING',
|
||||||
|
'@0@ @1@'.format(meson.project_name(), meson.project_version()),
|
||||||
|
)
|
||||||
|
|
||||||
|
if selinux_dep.found()
|
||||||
|
cdata.set('HAVE_SELINUX', 1)
|
||||||
|
if selinux_dep.version().version_compare('>=2.3')
|
||||||
|
cdata.set('HAVE_SELINUX_2_3', 1)
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
if get_option('require_userns')
|
||||||
|
cdata.set('ENABLE_REQUIRE_USERNS', 1)
|
||||||
|
endif
|
||||||
|
|
||||||
|
configure_file(
|
||||||
|
output : 'config.h',
|
||||||
|
configuration : cdata,
|
||||||
|
)
|
||||||
|
|
||||||
|
if meson.is_subproject()
|
||||||
|
bwrapdir = get_option('libexecdir')
|
||||||
|
|
||||||
|
if get_option('program_prefix') == ''
|
||||||
|
error('program_prefix option must be set when bwrap is a subproject')
|
||||||
|
endif
|
||||||
|
else
|
||||||
|
bwrapdir = get_option('bindir')
|
||||||
|
endif
|
||||||
|
|
||||||
|
bwrap = executable(
|
||||||
|
get_option('program_prefix') + 'bwrap',
|
||||||
|
[
|
||||||
|
'bubblewrap.c',
|
||||||
|
'bind-mount.c',
|
||||||
|
'network.c',
|
||||||
|
'utils.c',
|
||||||
|
],
|
||||||
|
install : true,
|
||||||
|
install_dir : bwrapdir,
|
||||||
|
dependencies : [selinux_dep, libcap_dep],
|
||||||
|
)
|
||||||
|
|
||||||
|
xsltproc = find_program('xsltproc', required : get_option('man'))
|
||||||
|
|
||||||
|
if xsltproc.found() and not meson.is_subproject()
|
||||||
|
custom_target(
|
||||||
|
'bwrap.1',
|
||||||
|
output : 'bwrap.1',
|
||||||
|
input : 'bwrap.xml',
|
||||||
|
command : [
|
||||||
|
xsltproc,
|
||||||
|
'--nonet',
|
||||||
|
'--stringparam', 'man.output.quietly', '1',
|
||||||
|
'--stringparam', 'funcsynopsis.style', 'ansi',
|
||||||
|
'--stringparam', 'man.th.extra1.suppress', '1',
|
||||||
|
'--stringparam', 'man.authors.section.enabled', '0',
|
||||||
|
'--stringparam', 'man.copyright.section.enabled', '0',
|
||||||
|
'-o', '@OUTPUT@',
|
||||||
|
'http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl',
|
||||||
|
'@INPUT@',
|
||||||
|
],
|
||||||
|
install : true,
|
||||||
|
install_dir : get_option('mandir') / 'man1',
|
||||||
|
)
|
||||||
|
endif
|
||||||
|
|
||||||
|
if not meson.is_subproject()
|
||||||
|
subdir('completions')
|
||||||
|
endif
|
47
meson_options.txt
Normal file
47
meson_options.txt
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
option(
|
||||||
|
'bash_completion',
|
||||||
|
type : 'feature',
|
||||||
|
description : 'install bash completion script',
|
||||||
|
value : 'enabled',
|
||||||
|
)
|
||||||
|
option(
|
||||||
|
'bash_completion_dir',
|
||||||
|
type : 'string',
|
||||||
|
description : 'install bash completion script in this directory',
|
||||||
|
value : '',
|
||||||
|
)
|
||||||
|
option(
|
||||||
|
'man',
|
||||||
|
type : 'feature',
|
||||||
|
description : 'generate man pages',
|
||||||
|
value : 'auto',
|
||||||
|
)
|
||||||
|
option(
|
||||||
|
'program_prefix',
|
||||||
|
type : 'string',
|
||||||
|
description : 'Prepend string to bwrap executable name, for use with subprojects',
|
||||||
|
)
|
||||||
|
option(
|
||||||
|
'require_userns',
|
||||||
|
type : 'boolean',
|
||||||
|
description : 'require user namespaces by default when installed setuid',
|
||||||
|
value : 'false',
|
||||||
|
)
|
||||||
|
option(
|
||||||
|
'selinux',
|
||||||
|
type : 'feature',
|
||||||
|
description : 'enable optional SELINUX support',
|
||||||
|
value : 'auto',
|
||||||
|
)
|
||||||
|
option(
|
||||||
|
'zsh_completion',
|
||||||
|
type : 'feature',
|
||||||
|
description : 'install zsh completion script',
|
||||||
|
value : 'enabled',
|
||||||
|
)
|
||||||
|
option(
|
||||||
|
'zsh_completion_dir',
|
||||||
|
type : 'string',
|
||||||
|
description : 'install zsh completion script in this directory',
|
||||||
|
value : '',
|
||||||
|
)
|
59
tests/meson.build
Normal file
59
tests/meson.build
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
test_programs = [
|
||||||
|
['test-utils', executable(
|
||||||
|
'test-utils',
|
||||||
|
'test-utils.c',
|
||||||
|
'../utils.c',
|
||||||
|
'../utils.h',
|
||||||
|
dependencies : [selinux_dep],
|
||||||
|
)],
|
||||||
|
]
|
||||||
|
|
||||||
|
test_scripts = [
|
||||||
|
'test-run.sh',
|
||||||
|
'test-seccomp.py',
|
||||||
|
'test-specifying-pidns.sh',
|
||||||
|
'test-specifying-userns.sh',
|
||||||
|
]
|
||||||
|
|
||||||
|
test_env = environment()
|
||||||
|
test_env.set('BWRAP', bwrap.full_path())
|
||||||
|
test_env.set('G_TEST_BUILDDIR', meson.current_build_dir())
|
||||||
|
test_env.set('G_TEST_SRCDIR', meson.current_source_dir())
|
||||||
|
|
||||||
|
foreach pair : test_programs
|
||||||
|
name = pair[0]
|
||||||
|
test_program = pair[1]
|
||||||
|
if meson.version().version_compare('>=0.50.0')
|
||||||
|
test(
|
||||||
|
name,
|
||||||
|
test_program,
|
||||||
|
env : test_env,
|
||||||
|
protocol : 'tap',
|
||||||
|
)
|
||||||
|
else
|
||||||
|
test(
|
||||||
|
name,
|
||||||
|
test_program,
|
||||||
|
env : test_env,
|
||||||
|
)
|
||||||
|
endif
|
||||||
|
endforeach
|
||||||
|
|
||||||
|
foreach test_script : test_scripts
|
||||||
|
if meson.version().version_compare('>=0.50.0')
|
||||||
|
test(
|
||||||
|
test_script,
|
||||||
|
bash,
|
||||||
|
args : [test_script],
|
||||||
|
env : test_env,
|
||||||
|
protocol : 'tap',
|
||||||
|
)
|
||||||
|
else
|
||||||
|
test(
|
||||||
|
test_script,
|
||||||
|
bash,
|
||||||
|
args : [test_script],
|
||||||
|
env : test_env,
|
||||||
|
)
|
||||||
|
endif
|
||||||
|
endforeach
|
2
tests/use-as-subproject/.gitignore
vendored
Normal file
2
tests/use-as-subproject/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
/_build/
|
||||||
|
/subprojects/
|
3
tests/use-as-subproject/README
Normal file
3
tests/use-as-subproject/README
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
This is a simple example of a project that uses bubblewrap as a
|
||||||
|
subproject. The intention is that if this project can successfully build
|
||||||
|
bubblewrap as a subproject, then so could Flatpak.
|
1
tests/use-as-subproject/config.h
Normal file
1
tests/use-as-subproject/config.h
Normal file
@@ -0,0 +1 @@
|
|||||||
|
#error Should not use superproject config.h to compile bubblewrap
|
1
tests/use-as-subproject/dummy-config.h.in
Normal file
1
tests/use-as-subproject/dummy-config.h.in
Normal file
@@ -0,0 +1 @@
|
|||||||
|
#error Should not use superproject generated config.h to compile bubblewrap
|
19
tests/use-as-subproject/meson.build
Normal file
19
tests/use-as-subproject/meson.build
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
project(
|
||||||
|
'use-bubblewrap-as-subproject',
|
||||||
|
'c',
|
||||||
|
version : '0',
|
||||||
|
meson_version : '>=0.49.0',
|
||||||
|
)
|
||||||
|
|
||||||
|
configure_file(
|
||||||
|
output : 'config.h',
|
||||||
|
input : 'dummy-config.h.in',
|
||||||
|
configuration : configuration_data(),
|
||||||
|
)
|
||||||
|
|
||||||
|
subproject(
|
||||||
|
'bubblewrap',
|
||||||
|
default_options : [
|
||||||
|
'program_prefix=not-flatpak-',
|
||||||
|
],
|
||||||
|
)
|
Reference in New Issue
Block a user