Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
  • 0.20240321.x
  • main
  • v0.20231013.x
  • wip/case_insensitive_fs
  • wip/denittis/line_based
  • wip/denittis/portal_helper
  • wip/denittis/t17372
  • wip/denittis/t20052
  • wip/denittis/t20177
  • wip/denittis/t7017
  • wip/denittis/tasks239
  • wip/denittis/up_libcapsule
  • wip/diagnose-task724
  • wip/fix_archlinux_ci
  • wip/flatpak_exports_for_run_host
  • wip/gameoverlayrenderer
  • wip/input-device-diagnostic
  • wip/input-portal
  • wip/issue18
  • wip/luigipiucco/nixos
  • wip/protected/ci
  • wip/protected/scout-on-soldier
  • wip/protected/smcv-ci
  • wip/protected/smcv-merge-slr
  • wip/protected/task679
  • wip/refi64/check-steam-running
  • wip/refi64/ci-coverage-demo
  • wip/refi64/mr_template_test
  • wip/refi64/openxr
  • wip/refi64/openxr-rt-pv
  • wip/refi64/openxr-sysinfo
  • wip/refi64/vk-layers
  • wip/regenerate-ldso-cache
  • wip/shorten_socket
  • wip/smcv/always-copy-runtime
  • wip/smcv/ci
  • wip/smcv/clang
  • wip/smcv/delete-in-background
  • wip/smcv/dev-lib-symlinks
  • wip/smcv/diagnose-sfl10602
  • wip/smcv/diffable
  • wip/smcv/doc
  • wip/smcv/docs
  • wip/smcv/fex-3
  • wip/smcv/gcc11
  • wip/smcv/guessed-library-arch
  • wip/smcv/inspect-library
  • wip/smcv/into-library
  • wip/smcv/ld-so-wrapper
  • wip/smcv/lxc
  • wip/smcv/no-nvidia-pkcs11
  • wip/smcv/pv-wrap-to-journal
  • wip/smcv/refcount-locks
  • wip/smcv/relocatable-bin
  • wip/smcv/spawn-really-async
  • wip/smcv/staging
  • wip/smcv/steam-portal
  • wip/smcv/task149-nonfhs
  • wip/smcv/task212-basename
  • wip/smcv/task370-debug
  • wip/smcv/test-diagnostics
  • wip/smcv/variant-init-statically
  • wip/smcv/vulkan-1-1
  • wip/sr640
  • wip/sr684
  • wip/task293-v1
  • wip/task342-3
  • wip/task466
  • wip/task466-more
  • wip/task481-test
  • wip/task488-test
  • wip/task595
  • wip/task634
  • wip/task647
  • wip/task88
  • wip/task88-pre
  • wip/vulkan_shaders
  • wip/xytovl/openxr
  • pressure-vessel-v0.20180430.0
  • pressure-vessel-v0.20180517.0
  • pressure-vessel-v0.20180517.1
  • pressure-vessel-v0.20180518.0
  • pressure-vessel-v0.20180518.1
  • pressure-vessel-v0.20190510.0
  • pressure-vessel-v0.20190815.0
  • pressure-vessel-v0.20190819.0
  • pressure-vessel-v0.20190820.0
  • pressure-vessel-v0.20190822.0
  • pressure-vessel-v0.20190823.0
  • pressure-vessel-v0.20190912.0
  • pressure-vessel-v0.20190926.0
  • pressure-vessel-v0.20190927.0
  • pressure-vessel-v0.20191112.0
  • pressure-vessel-v0.20191112.1
  • pressure-vessel-v0.20191115.0
  • pressure-vessel-v0.20191216.0
  • pressure-vessel-v0.20200108.0
  • pressure-vessel-v0.20200331.0
  • pressure-vessel-v0.20200624.0
  • pressure-vessel-v0.20200708.0
  • pressure-vessel-v0.20200709.0
  • pressure-vessel-v0.20200805.0
  • pressure-vessel-v0.20200819.0
  • pressure-vessel-v0.20200908.0
  • pressure-vessel-v0.20200909.0
  • steamrt/0.20190926.0-0+steamrt1.2
  • v0.20190717.0
  • v0.20190801.0
  • v0.20190802.0
  • v0.20190806.0
  • v0.20190816.0
  • v0.20190820.0
  • v0.20190820.1
  • v0.20190822.0
  • v0.20190909.0
  • v0.20190926.0
  • v0.20190926.1
  • v0.20191024.0
  • v0.20191120.0
  • v0.20191205.0
  • v0.20191209.0
  • v0.20200108.0
  • v0.20200109.0
  • v0.20200306.0
  • v0.20200331.0
  • v0.20200331.1
  • v0.20200415.0
  • v0.20200624.0
  • v0.20200908.0
  • v0.20200908.1
  • v0.20200914.0
  • v0.20201002.0
  • v0.20201007.0
  • v0.20201022.0
  • v0.20201124.0
  • v0.20201203.0
  • v0.20210105.0
  • v0.20210114.0
  • v0.20210126.0
  • v0.20210201.0
  • v0.20210203.0
  • v0.20210305.0
  • v0.20210312.0
  • v0.20210317.0
  • v0.20210331.0
  • v0.20210415.0
  • v0.20210430.0
  • v0.20210518.0
  • v0.20210608.0
  • v0.20210608.1
  • v0.20210608.2
  • v0.20210608.3
  • v0.20210617.0
  • v0.20210617.1
  • v0.20210630.0
  • v0.20210722.0
  • v0.20210806.0
  • v0.20210809.0
  • v0.20210809.1
  • v0.20210820.0
  • v0.20210906.0
  • v0.20210906.1
  • v0.20210906.2
  • v0.20211027.0
  • v0.20211207.0
  • v0.20220107.0
  • v0.20220111.0
  • v0.20220119.0
  • v0.20220131.0
  • v0.20220311.0
  • v0.20220315.0
  • v0.20220420.0
  • v0.20220601.0
  • v0.20220620.0
  • v0.20220624.0
  • v0.20220725.0
  • v0.20220725.1
  • v0.20220726.0
178 results

Target

Select target project
  • steamrt/steam-runtime-tools
1 result
Select Git revision
  • 0.20240321.x
  • main
  • v0.20231013.x
  • wip/case_insensitive_fs
  • wip/denittis/line_based
  • wip/denittis/portal_helper
  • wip/denittis/t17372
  • wip/denittis/t20052
  • wip/denittis/t20177
  • wip/denittis/t7017
  • wip/denittis/tasks239
  • wip/denittis/up_libcapsule
  • wip/diagnose-task724
  • wip/fix_archlinux_ci
  • wip/flatpak_exports_for_run_host
  • wip/gameoverlayrenderer
  • wip/input-device-diagnostic
  • wip/input-portal
  • wip/issue18
  • wip/luigipiucco/nixos
  • wip/protected/ci
  • wip/protected/scout-on-soldier
  • wip/protected/smcv-ci
  • wip/protected/smcv-merge-slr
  • wip/protected/task679
  • wip/refi64/check-steam-running
  • wip/refi64/ci-coverage-demo
  • wip/refi64/mr_template_test
  • wip/refi64/openxr
  • wip/refi64/openxr-rt-pv
  • wip/refi64/openxr-sysinfo
  • wip/refi64/vk-layers
  • wip/regenerate-ldso-cache
  • wip/shorten_socket
  • wip/smcv/always-copy-runtime
  • wip/smcv/ci
  • wip/smcv/clang
  • wip/smcv/delete-in-background
  • wip/smcv/dev-lib-symlinks
  • wip/smcv/diagnose-sfl10602
  • wip/smcv/diffable
  • wip/smcv/doc
  • wip/smcv/docs
  • wip/smcv/fex-3
  • wip/smcv/gcc11
  • wip/smcv/guessed-library-arch
  • wip/smcv/inspect-library
  • wip/smcv/into-library
  • wip/smcv/ld-so-wrapper
  • wip/smcv/lxc
  • wip/smcv/no-nvidia-pkcs11
  • wip/smcv/pv-wrap-to-journal
  • wip/smcv/refcount-locks
  • wip/smcv/relocatable-bin
  • wip/smcv/spawn-really-async
  • wip/smcv/staging
  • wip/smcv/steam-portal
  • wip/smcv/task149-nonfhs
  • wip/smcv/task212-basename
  • wip/smcv/task370-debug
  • wip/smcv/test-diagnostics
  • wip/smcv/variant-init-statically
  • wip/smcv/vulkan-1-1
  • wip/sr640
  • wip/sr684
  • wip/task293-v1
  • wip/task342-3
  • wip/task466
  • wip/task466-more
  • wip/task481-test
  • wip/task488-test
  • wip/task595
  • wip/task634
  • wip/task647
  • wip/task88
  • wip/task88-pre
  • wip/vulkan_shaders
  • wip/xytovl/openxr
  • pressure-vessel-v0.20180430.0
  • pressure-vessel-v0.20180517.0
  • pressure-vessel-v0.20180517.1
  • pressure-vessel-v0.20180518.0
  • pressure-vessel-v0.20180518.1
  • pressure-vessel-v0.20190510.0
  • pressure-vessel-v0.20190815.0
  • pressure-vessel-v0.20190819.0
  • pressure-vessel-v0.20190820.0
  • pressure-vessel-v0.20190822.0
  • pressure-vessel-v0.20190823.0
  • pressure-vessel-v0.20190912.0
  • pressure-vessel-v0.20190926.0
  • pressure-vessel-v0.20190927.0
  • pressure-vessel-v0.20191112.0
  • pressure-vessel-v0.20191112.1
  • pressure-vessel-v0.20191115.0
  • pressure-vessel-v0.20191216.0
  • pressure-vessel-v0.20200108.0
  • pressure-vessel-v0.20200331.0
  • pressure-vessel-v0.20200624.0
  • pressure-vessel-v0.20200708.0
  • pressure-vessel-v0.20200709.0
  • pressure-vessel-v0.20200805.0
  • pressure-vessel-v0.20200819.0
  • pressure-vessel-v0.20200908.0
  • pressure-vessel-v0.20200909.0
  • steamrt/0.20190926.0-0+steamrt1.2
  • v0.20190717.0
  • v0.20190801.0
  • v0.20190802.0
  • v0.20190806.0
  • v0.20190816.0
  • v0.20190820.0
  • v0.20190820.1
  • v0.20190822.0
  • v0.20190909.0
  • v0.20190926.0
  • v0.20190926.1
  • v0.20191024.0
  • v0.20191120.0
  • v0.20191205.0
  • v0.20191209.0
  • v0.20200108.0
  • v0.20200109.0
  • v0.20200306.0
  • v0.20200331.0
  • v0.20200331.1
  • v0.20200415.0
  • v0.20200624.0
  • v0.20200908.0
  • v0.20200908.1
  • v0.20200914.0
  • v0.20201002.0
  • v0.20201007.0
  • v0.20201022.0
  • v0.20201124.0
  • v0.20201203.0
  • v0.20210105.0
  • v0.20210114.0
  • v0.20210126.0
  • v0.20210201.0
  • v0.20210203.0
  • v0.20210305.0
  • v0.20210312.0
  • v0.20210317.0
  • v0.20210331.0
  • v0.20210415.0
  • v0.20210430.0
  • v0.20210518.0
  • v0.20210608.0
  • v0.20210608.1
  • v0.20210608.2
  • v0.20210608.3
  • v0.20210617.0
  • v0.20210617.1
  • v0.20210630.0
  • v0.20210722.0
  • v0.20210806.0
  • v0.20210809.0
  • v0.20210809.1
  • v0.20210820.0
  • v0.20210906.0
  • v0.20210906.1
  • v0.20210906.2
  • v0.20211027.0
  • v0.20211207.0
  • v0.20220107.0
  • v0.20220111.0
  • v0.20220119.0
  • v0.20220131.0
  • v0.20220311.0
  • v0.20220315.0
  • v0.20220420.0
  • v0.20220601.0
  • v0.20220620.0
  • v0.20220624.0
  • v0.20220725.0
  • v0.20220725.1
  • v0.20220726.0
178 results
Show changes
Showing
with 1741 additions and 0 deletions
usr/lib/libcapsule/relocatable
usr/bin/*-capsule-capture-libs
usr/bin/*-capsule-elf-dump
usr/bin/*-capsule-mkstublib
usr/bin/*-capsule-symbols
usr/bin/*-capsule-version
usr/bin/capsule-init-project
usr/lib/*/pkgconfig/libcapsule-tools.pc
usr/share/libcapsule/*
usr/share/man/man1/*
usr/lib/*/libcapsule.so.0
usr/lib/*/libcapsule.so.0.*
libcapsule.so.0 libcapsule0 #MINVER#
* Build-Depends-Package: libcapsule-dev
capsule_close@Base 0.20180430.0
capsule_external_dlopen@Base 0.20180430.0
capsule_external_dlsym@Base 0.20180430.0
capsule_get_prefix@Base 0.20180430.0
capsule_init@Base 0.20180430.0
capsule_shim_dlopen@Base 0.20180430.0
capsule_shim_free@Base 0.20180430.0
capsule_shim_realloc@Base 0.20180430.0
#!/usr/bin/make -f
-include /usr/share/dpkg/default.mk
%:
dh $@ --with autoreconf
binaries := $(shell dh_listpackages)
fake_rpath := /_ORIGIN_/__/lib/${DEB_HOST_MULTIARCH}
real_rpath := $${ORIGIN}/../lib/${DEB_HOST_MULTIARCH}
confflags = \
--disable-Werror \
--disable-silent-rules \
--enable-host-prefix=$(DEB_HOST_MULTIARCH)- \
--enable-tools-rpath='${fake_rpath}' \
--libexecdir=\$${exec_prefix}/lib/libcapsule \
$(NULL)
ifneq ($(filter libcapsule-doc,$(binaries)),)
confflags += --enable-gtk-doc
else
confflags += --disable-gtk-doc
endif
ifeq ($(DEB_HOST_ARCH),amd64)
confflags += --with-glib=auto
else
confflags += --without-glib
endif
override_dh_clean:
rm -fr html
dh_clean
override_dh_auto_configure:
dh_auto_configure -- $(confflags)
proxy_vars = \
CAPSULE_CFLAGS="-I$(CURDIR)" \
CAPSULE_LIBS="-L$(CURDIR)/.libs -lcapsule" \
CAPSULE_MKINC="$(CURDIR)/data" \
CAPSULE_MKSTUBLIB_TOOL="$(CURDIR)/data/capsule-mkstublib" \
CAPSULE_SYMBOLS_TOOL="$(CURDIR)/capsule-symbols" \
CAPSULE_VERSION_TOOL="$(CURDIR)/capsule-version" \
$(NULL)
override_dh_auto_build:
dh_auto_build
$(proxy_vars) ./data/capsule-init-project \
--capsule-pkgdatadir="$(CURDIR)/data" \
--destination="$(CURDIR)/debian/libGL-proxy" \
--no-autoreconf \
--package-name=libGL-proxy \
--search-tree=/nonexistent \
--symbols-from-dir="$(CURDIR)/examples/shim" \
libGL.so.1/1 \
libX11.so.6/6 \
libXext.so.6/6 \
libXi.so.6/6 \
libxcb-dri2.so.0/0 \
libxcb-glx.so.0/0 \
libxcb-present.so.0/0 \
libxcb-sync.so.1/1 \
libxcb.so.1/1 \
$(NULL)
# Copy it, so we can install the original source as an example
cp -a debian/libGL-proxy debian/libGL-proxy-build
cd debian/libGL-proxy-build && autoreconf -fi -I $(CURDIR)/m4
cd debian/libGL-proxy-build && ./configure --prefix=/usr $(proxy_vars)
$(MAKE) -C debian/libGL-proxy-build V=1 $(proxy_vars)
override_dh_auto_install:
dh_auto_install
if [ $(DEB_HOST_MULTIARCH) != $(DEB_HOST_GNU_TYPE) ]; then \
set -e; \
cd debian/tmp/usr/bin; \
for bin in $(DEB_HOST_MULTIARCH)-*; do \
tail="$${bin#$(DEB_HOST_MULTIARCH)-}"; \
ln -s "$$bin" "$(DEB_HOST_GNU_TYPE)-$$tail"; \
done; \
fi
install -d debian/tmp/usr/lib/libcapsule/relocatable
cp -a \
debian/tmp/usr/bin/*-capsule-capture-libs \
debian/tmp/usr/bin/*-capsule-elf-dump \
debian/tmp/usr/bin/*-capsule-symbols \
debian/tmp/usr/bin/*-capsule-version \
debian/tmp/usr/lib/libcapsule/relocatable
set -e; for bin in debian/tmp/usr/bin/$(DEB_HOST_MULTIARCH)-*; do \
case "$$bin" in \
(*-capsule-mkstublib) \
;; \
(*) \
chrpath -d "$$bin"; \
chrpath -l "$$bin" || :; \
;; \
esac; \
done
chrpath -r '${real_rpath}' \
debian/tmp/usr/lib/libcapsule/relocatable/$(DEB_HOST_MULTIARCH)-*
chrpath -l debian/tmp/usr/lib/libcapsule/relocatable/*
$(MAKE) -C debian/libGL-proxy-build install V=1 $(proxy_vars) \
DESTDIR=$(CURDIR)/debian/libGL-proxy-build/shims
install -d debian/tmp/usr/lib/libcapsule/shims/lib/$(DEB_HOST_MULTIARCH)
mv debian/libGL-proxy-build/shims/usr/lib/* \
debian/tmp/usr/lib/libcapsule/shims/lib/$(DEB_HOST_MULTIARCH)
override_dh_install:
rm -f debian/tmp/usr/lib/*/*.la
rm -f debian/tmp/usr/lib/libcapsule/shims/lib/*/*.la
find debian/tmp/usr/lib/libcapsule/installed-tests -name '*.la' -print -delete
# Only keep the architecture-qualified version, delete the unprefixed
# version, so we can be Multi-Arch: same
rm -f debian/tmp/usr/bin/capsule-capture-libs
rm -f debian/tmp/usr/bin/capsule-elf-dump
rm -f debian/tmp/usr/bin/capsule-symbols
rm -f debian/tmp/usr/bin/capsule-version
dh_install
# The debug symbols for libcapsule-tools-relocatable would be the same
# as for libcapsule-tools, making them non-co-installable.
# Use the environment variable instead of --no-automatic-dbgsym for
# compatibility with Steam Runtime 1 'scout'.
override_dh_strip:
DEB_BUILD_OPTIONS='$(DEB_BUILD_OPTIONS) noautodbgsym' dh_strip -plibcapsule-tools-relocatable
dh_strip --remaining-packages
override_dh_missing:
dh_missing --fail-missing
override_dh_autoreconf:
NOCONFIGURE=1 dh_autoreconf ./autogen.sh -- $(confflags)
3.0 (quilt)
Tests: gnome-desktop-testing smoke
Restrictions: allow-stderr
Depends:
autoconf,
automake,
bubblewrap,
build-essential,
gnome-desktop-testing,
libcapsule-dev,
libcapsule-tests,
libcapsule-tools,
libipc-run-perl,
libglib2.0-0,
libxml2,
libtool,
perl,
pkg-config,
zlib1g,
#!/bin/sh
set -e
exec 2>&1
exec gnome-desktop-testing-runner libcapsule
#!/usr/bin/perl
# Copyright © 2017 Collabora Ltd.
#
# This library is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as
# published by the Free Software Foundation; either version 2.1 of the
# License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library. If not, see <http://www.gnu.org/licenses/>.
use autodie;
use File::Temp qw();
use IPC::Run qw(run);
use Test::More;
my $scratch = File::Temp->newdir();
chdir($scratch);
open(my $fh, '>', 'trivial.c');
print {$fh} <<'EOF';
#define _GNU_SOURCE
#include <stdio.h>
#include <capsule/capsule.h>
int
main (void)
{
char *prefix = capsule_get_prefix( "/host", "libfoo.so.0" );
printf( "%s\n", prefix );
return 0;
}
EOF
close($fh);
ok(! system('gcc -c -o trivial.o trivial.c $(pkg-config --cflags libcapsule)'),
'compiled');
ok(! system('gcc -o trivial trivial.o $(pkg-config --libs libcapsule)'),
'linked');
ok(-x 'trivial', 'executable');
my $output;
$ENV{CAPSULE_LIBFOO_SO_0_PREFIX} = '/foo';
ok(run(['./trivial'], '>', \$output), 'executed successfully');
is($output, "/foo\n", 'printed desired output');
chdir('/');
done_testing;
Building libcapsule from git requires GNU autoconf-archive macros. The
oldest supported version is 20180313-1 from Debian 9 'stretch'. If your
development system or container is older, unpack or clone a suitable
version of autoconf-archive and use commands like:
libcapsule$ ACLOCAL_PATH=/path/to/autoconf-archive/m4 NOCONFIGURE=1 ./autogen.sh
libcapsule$ ./configure
libcapsule$ make
Building from tarball releases removes this requirement.
libcapsule provides a few tools to help initialise a proxy library project:
Assuming a host tree containing libGL mounted at /host, the simplest route
to a [hopefully] working project is as follows:
~$ $(pkg-config --variable=CAPSULE_INIT_PROJECT_TOOL libcapsule-tools) libGL.so.1 /host
Generating project for /host : libGL.so.1 1.2.0 proxy
Creating project directory libGL-proxy
Working in /home/vivek/src/valve/dlmopen/libGL-proxy
Extracting dynamic symbols from /host : libGL.so.1
Preparing proxy source files
Initialising configure.ac
Initialising Makefile.am
Bootstrapping autoconf templates for libGL.so.1
Running initial configuration
autoreconf: Entering directory `.'
autoreconf: configure.ac: not using Gettext
autoreconf: running: aclocal --force
autoreconf: configure.ac: tracing
autoreconf: running: libtoolize --copy --force
libtoolize: putting auxiliary files in `.'.
libtoolize: copying file `./ltmain.sh'
libtoolize: putting macros in AC_CONFIG_MACRO_DIR, `m4'.
libtoolize: copying file `m4/libtool.m4'
libtoolize: copying file `m4/ltoptions.m4'
libtoolize: copying file `m4/ltsugar.m4'
libtoolize: copying file `m4/ltversion.m4'
libtoolize: copying file `m4/lt~obsolete.m4'
libtoolize: Consider adding `-I m4' to ACLOCAL_AMFLAGS in Makefile.am.
autoreconf: running: /usr/bin/autoconf --force
autoreconf: configure.ac: not using Autoheader
autoreconf: running: automake --add-missing --copy --force-missing
Makefile.am: installing './depcomp'
autoreconf: Leaving directory `.'
/home/x/src/valve/dlmopen/libGL-proxy is ready for ./configure, \
see README for details
This will set up a project to build a proxy for libGL.so.1, expected
to be found in a foreign filesystem tree mounted at /host.
The target library (the real libGL.so.1) must be present in a well-formed
tree mounted at /host at the point at which you run this command.
If you ever make changes which require the proxy library source files
to be regenerated (changing the foreign tree location from /host or
altering the list of symbols to export) then the foreign tree must
likewise be present.
However you do not need the tree to be present to build the library itself
once the project has been initialised.
The layout of the project will be as follows:
./shim/
./shim/libGL.so.1.shared
./shim/libGL.so.1.dlopen
./shim/libGL.so.1.symbols.updated-for
./shim/libGL.so.1.excluded
./shim/libGL.so.1.dlsym
./configure
./build-aux/…
./m4/…
./README
./dd.log
./preconfigure.log
./Makefile.am
./configure.ac
./aclocal.m4
./arena.log
./Makefile.in
A few of these files are of immediate interest:
----------------------------------------------------------------------------
preconfigure.log:
This records the initial bootstrapping step of the project, which uses
autoconf to set up the build system from libcapsule's templates.
If things are working, there's little of interest here, but if something's
not quite right there may be important clues recorded here.
----------------------------------------------------------------------------
Makefile.am
A few important details are recorded here:
CAPSULE_LIBRARY - The stub of the library name (‘GL’ in this case).
CAPSULE_VERSION_libfoo.so.0 -
The version number of the proxy library for libfoo.so.0
defaults to the same version as the library in /host
if that can be deduced from the /host tree.
Only the major version (major.minor.sub) needs to match,
otherwise you may change this as desired.
CAPSULE_TREE - The location of the foreign tree.
You may change this, but doing so requires the source
to be regenerated, which requires the new foreign tree
to be present.
CAPSULE_MAJOR - Major version of the library we're encapsulating
----------------------------------------------------------------------------
shim/libGL.so.1.excluded
This file should contain a list of libraries which should _NOT_
be picked up from the /host tree and isolated in the capsule,
one per line.
The following library is always considered to be excluded by
the code generator, so there's no need to add it explicitly:
libdl.so.2
Other libraries which you may need to add, depending on the exact
API presented by the proxied library, are:
libc.so.6 - if memory allocated inside the target library
is freed by the main program, or similar.
libpthread.so.0 - if thread synchronisation or similar occurs
libpthread-2.19.so both inside the proxied library and your main
program AND the two need to be aware of one
another.
----------------------------------------------------------------------------
shim/libGL.so.1.shared
This file should contain any extra libraries whose symbols should _also_ be
exported from the capsule, along with those from the main library libGL.so.
It will generally be empty, but in libGL.so's case it must contain:
libxcb.so.1
libxcb-glx.so.0
libxcb-dri2.so.0
libxcb-dri3.so.0
libxcb-present.so.0
libxcb-sync.so.1
libX11.so
Every time this file is modified, you will need to run
make maintainer-update-capsule-symbols
to update the list of exported symbols in shim/libGL.so.1.symbols.
This will also update shim/libGL.so.1.symbols.updated-for to record
the fact that it does not need updating again. You can use
make maintainer-update-capsule-symbols CAPSULE_SEARCH_TREE=/sysroot
to specify a custom root directory to search for these libraries.
----------------------------------------------------------------------------
shim/capsule/_int_dlopen.h
This file is not created by default.
The _int_dlopen wrapper is installed inside the capsule and takes
care of any /host path prefixing so that the encapsulated libraries
get their native targets with dlmopen (and don't break encapsulation
by calling dlopen).
A default implementation provided by libcapsule is normally used.
See libcapsule's <capsule/_int_dlopen.h> for that implementation.
To use a custom implementation, create the file and implement a
function with the same signature:
static void *_int_dlopen (const char *filename, int flags)
{
}
----------------------------------------------------------------------------
That's it - you should be ready to:
./configure
make
Your generated capsule libraries will be in .libs,
and you can use ‘make install’ et al, as usual, to install them.
Note that you should be careful about this, as you are deliberately
generating a library which has the same name as a ‘real’ one, which
is very much not a normal situation, and carelessness here could break
your system.
This document covers the details of how libcapsule manages proxy capsule
libraries.
For details of how symbol hiding/relocation is done, see Strategy.txt.
============================================================================
Summary:
Each capsule library acts as a shim for at least one target library, with
which it shares a soname, and whose symbols it exports to the libraries
that link to it (both at dynamic link time and via dlopen/dlsym).
Capsules _may_ act as a shim for more than one library, but they can have
only one soname: This pattern of use was necessary during the early
development of libcapsule when we supported at most one capsule in any
given link chain but is no longer required.
============================================================================
Details:
Each capsule library must
a) depend on libcapsule (ie have libcapsule in a DT_NEEDED entry)
b) #include "capsule/capsule-shim.h"
c) declare a globally visible symbol called capsule_meta which should
be a populated struct of type capsule_metadata
NOTE: it should not attempt to use this variable, only
the handle returned by capsule_init(). That handle will be
initialised based on the metadata.
d) declare UNVERSIONED_STUB( f ); for each function ‘f’ it wishes to proxy
e) declare a static global variable:
static capsule cap;
f) In its constructor:
assign the return of capsule_init to ‘cap’
g) In its destructor:
call capsule_close
============================================================================
Metadata example (for a libGL.so.1 capsule):
static const char *exclude[] =
{ // MUST NOT be pulled from the capsule
// prefixed filesystem tree:
"libdl.so.2",
NULL
};
// make sure this symbol has global visibility so
// that the libcapsule initialisation can find it
__attribute__ ((visibility("default")))
capsule_metadata capsule_meta =
{
.capsule_abi = 0,
.soname = "libGL.so.1",
.default_prefix = "/host",
.exclude = exclude,
.export = valid_dlsym_sources,
};
============================================================================
Sequences of events:
Normal linking
A library or executable using a capsule is loaded
The linker notes that the capsule is listed in DT_NEEDED and loads it
The linker notes that libcapsule is DT_NEEDED by the capsule and loads _that_
(if it is not already loaded).
Various libraries are loaded - once all DT_NEEDEDs have been satisfied:
The constructors for the loaded DSOs run in reverse dependency order,
in particular:
The constructor for libcapsule runs, and does the following:
- harvests metadata from all currently loaded capsules and caches them
- caches the addresses of the default implementations of dlopen and dlsym
- groups the metadata by filesystem prefix
- all capsules that specify /foo as their prefix will be grouped into
the same private namespace
- a capsule's prefix is determined by (in descending priority)
- the soname specific env var (eg CAPSULE_LIBGL_SO_1_PREFIX)
- the CAPSULE_PREFIX env var
- the static prefix in the capsule's metadata
- NOTE: env vars don't apply here to setuid/setgid processes,
or if libcapsule was compiled using glibc older than 2.17
- aggregates the exclude and export metadata lists, grouping
them by prefix (and deduplicating the resulting lists)
- eg the ‘export’ list from a namespace will be all the sonames from
all the .export entries from all capsules that share that namespace
(as determined by their prefix)
The constructor for each loaded capsule runs and calls
capsule_init( static-copy-of-soname ) which does the following:
- calls _capsule_load to load the real target library
- calls _capsule_relocate to update the global offset tables (GOTs)
of all DSOs outside the capsule to use the real symbols from the
target instead of the dummy entries in the capsule
- calls _capsule_relocate_dlopen to install wrappers for any special-case
functions (typically just dlopen - dlsym is handled by _capsule_relocate)
that require careful handling.
dlopen() of a capsule (from outside the capsule):
This is similar to normal linking, except:
- The libcapsule constructor does not run
- the capsule's constructor's call to capsule_init triggers a re-harvesting
of available metadata, and a re-calculation of the aggregated lists
- the _capsule_relocate and _capsule_relocate_dlopen sequences for _all_
capsules are triggered
dlopen() of a normal library (from outside the capsule):
- the _capsule_relocate and _capsule_relocate_dlopen sequences for _all_
capsules are triggered
dlopen() of a normal library inside the capsule:
- secretly translated into a capsule_shim_dlopen call
dlopen() of a capsule from inside the capsule:
- cats and dogs living together
- total chaos
- the end of the world
dlsym() from inside the capsule:
- nothing special, works as normal
- this might break if dlsym is called on the NULL handle
with the expectation that the calling namespace and
public namespace are the same
dlsym() from outside the capsule
- handled by the wrapper we installed earlier
- looks first inside each capsule namespace for the requested symbol
- if said symbol is found _and_ comes from a DSO in the export list
then it is returned
- otherwise we fall back to vanilla dlsym
If you wish to debug the library loading & symbol proxying process
libcapsule exposes a lot of detail depending on the contents of the
CAPSULE_DEBUG environment variable.
CAPSULE_DEBUG is a comma-or-space separated variable, and currently
understand the following debug flags:
path : path manipulation and translation
search : searching for DSOs
ldcache : loading/processing the ld cache
capsule : setting up the proxy capsule
mprotect: subverting mprotect (for RELRO linking)
wrappers: function wrappers installed in the capsule
reloc : patching capsule symbols into external DSOs
dlfunc : dlsym/dlfunc wrapper info as they execute (overlaps wrappers)
elf : detailed ELF introspection logging
all : all of the above
At this point gdb does not yet know about dlmopen()ed DSOs and their
symbols, so debugging a libcapsule proxy library with gdb isn't very
convenient. It's on the list of things to fix.
If you are debugging the unit tests, you might want to set
CAPSULE_TESTS_KEEP_TEMP to a non-empty value so temporary
directories will not be cleaned up. See tests/CapsuleTest.pm
or `perldoc -F tests/CapsuleTest.pm` for more details.
libcapsule currently has the following limitations:
============================================================================
If there are > 1 copies of a library which handles allocation (eg
libstdc++) the capsule cannot protect you from an object allocated
by the encapsulated copy being freed by the public copy.
Some libraries may be OK with this pattern of behaviour, others
may not.
============================================================================
There can only ever be one copy of libdl shared between the capsule
and the public namespace. This behaviour is baked into the stub library
generator script. Probably nothing particularly sane will happen if you
try to ignore this limitation.
============================================================================
Currently only functions are exported from the capsule. Unlike the
previous items, this limitation is not intrinsic and could be lifted.
============================================================================
libcapsule relies on the ld.so.cache from the capsule tree to find
libraries. If the cache is not there, it may still find some libraries
in the default-standard locations but many paths will end up being ignored.
============================================================================
libcapsule replaces any instances of dlopen in the encapsulated libraries
with a wrapper around dlmopen: It does this so that a capsule opened on the
"/host" prefix (for example) continues to use DSOs (libraries and modules)
from "/host", and to prevent dlopen() calls from within the capsule from
breaking encapsulation.
NB: Currently a dlopen() call from inside a dlmopen() namespace is unsupported
by glibc anyway, and would result in a segfault.
============================================================================
Related to the above: The dlmopen wrapper cannot support RTLD_GLOBAL.
If the library you are opening relies on calling dlopen() with RTLD_GLOBAL
to expose symbols from one DSO to another it will not work.
This is a glibc limitation - it could be lifted but would require
the dlmopen libc call (and the linker) to be modified.
============================================================================
If you are using Mesa before v 17.x you will need to use `patchelf' v0.9
or later to add a DT_NEEDED entry for libglapi.so.0 to your dri.so drivers
in order for the libGL capsule to be able to work (assuming it is
libGL.so tat you are trying to proxy).
============================================================================
In the top level directory:
autoreconf -ivf
./configure
make
libcapsule.so will be in .libs/
The test environment is currently:
A chroot containing a debian/jessie filesystem with libGL.so removed,
the libcapsule .deb installed and with the "real" OS filesystem bind
mounted at /host.
In the chroot:
Generate a proxy project for libGL and related libraries:
~$ mkdir proxies
~$ cd proxies
~$ CAPTOOL=$(pkg-config --variable=CAPSULE_INIT_PROJECT_TOOL libcapsule-tools)
~$ LIBS="xcb.so.1 xcb-glx.so.0 xcb-dri2.so.0 xcb-dri3.so.0 xcb-present.so.0"
~$ LIBS="$LIBS xcb-sync.so.1 X11.so.6 GL.so.1 Xext.so.6"
~$ for x in $LIBS; do $CAPTOOL lib$x /host; done
~$ for x in *-proxy; do (cd $x && ./configure --prefix=/shim) || break; done
~$ for x in *-proxy; do (cd $x && make) || break; done
~$ for x in *-proxy; do (cd $x && sudo make install) || break; done
Now make said proxy libraries available. You should also:
Ensure that ldd $(which glxgears) points to the libGL.so capsule
Make sure a full filesystem from the host OS is mounted at /host
~$ export LD_LIBRARY_PATH=/shim/lib
~$ export DISPLAY=:0 # if you need this
Make sure your chroot is set up so that trivial XOrg programs can run
(xterm, xev, xeyes or whatever).
Run glxgears (or openarena, or whatever).
If it fails:
export CAPSULE_DEBUG=path,search,capsule,mprotect,wrappers,ldcache
glxgears 2>&1 | tee glxgears.capsule.log
capsule debug flags:
path # path manipulation and translation
search # searching for DSOs
ldcache # loading/processing the ld cache
capsule # setting up the proxy capsule
mprotect # handling mprotect (for RELRO)
wrappers # function wrappers installed in the capsule
reloc # patching capsule symbols into external DSOs
elf # detailed ELF introspection logging
NOTE: If your Mesa is older than 17.x, see the final item regarding patchelf
in the Limitations.txt file for a workaround.
TODO: add instructions for bwrap instead of chroot here.
Everything You Never Wanted To Know About Dynamic Linking:
----------------------------------------------------------------------------
If you have gotten this far you're probably interested in how
libcapsule does what it does: There's a lot of ground to cover
and there are many pieces of the puzzle but we'll try to explain
them all here.
The background:
----------------------------------------------------------------------------
First, a simplified outline of dynamic linking: When a program is
loaded, its type is determined. If it is ‘dynamically linked’, it
will contain a list of libraries (DSOs or Dynamically Shared Objects)
that it needs. Each of these DSOs will in turn contain a list
of its own dependencies (more DSOs).
The component of your system known as the linker will assemble the
full list of all the required DSOs, open them, and following a
somewhat intricate set of rules, copy (map) chunks of these files
into memory.
It then goes through every loaded DSO and fixes up each one by
scribbling the relevant addresses into its (the DSO's) lookup
table so that it can find the functions and variables (symbols)
it needs to from each of its dependencies.
Once this is done, the program is good to go: The system can
start executing its instructions, jumping between the loaded
DSOs (via the lookup tables in each one) as required.
The problem:
----------------------------------------------------------------------------
So far so good: This is mostly the right thing to do, and solves
a lot of problems we won't discuss here - But it does make some
important assumptions. One these is the following:
- that every DSO involved that requires a specific DSO is going to be
happy with the same copy of the same version of that requirement.
In other words if a program needs libfoo.so and both the program
and libfoo.so require libbar.so, they will both be happy with a
single copy of libbar.so v3.14.159 (for example) provided by the
linker.
This assumption is mostly true. In general things are happier when
everything is built on the same set of libraries, but occasionally
you can end up with a program that has conflicting requirements
for the same DSO - libcapsule tries to solve that problem.
The approach (the basics):
----------------------------------------------------------------------------
There are broadly two parts to the segregated-linker behaviour that we
require:
The first and more fundamental is mapping in the DSOs we wish to isolate
in such a way that the linker does not (by default) use their symbols'
addresses to fill in the lookup tables of the other DSOs we have loaded.
Fortunately this part of the problem is addresses by the [relatively]
new dlmopen() C library call. dlmopen() is similar to the dlopen() call,
except that instead of opening a DSO (and all its dependencies) into the
default linker namespace it does so into a private one, either creating
a new namespace if requested, or using an existing namespace. [ There are
one or two intricacies to this that we've glossed over here: We'll revisit
this in greater detail later. ]
The second part is making just the symbols we want available to the rest
of the DSOs our program consists of, ideally introducing as little overhead
as possible: There are a couple of approaches we could take to this,
each with problems of its own.
dlmopen() (the gory details):
----------------------------------------------------------------------------
When dlmopen() is called, the algorithm is roughly as follows:
• find the requested DSO
◦ if the path to the requested DSO is absolute, look for it there
◦ if the path is relative (contains but does not begin with '/')
then look for it relative to the processes current working directory
◦ if the path is bare, search for it using the standard linker algorithm:
‣ look in RPATH baked into DSO (if there's no RUNPATH)
‣ then LD_LIBRARY_PATH from environment
‣ then RUNPATH baked into DSO
‣ then contents of ld.so.cache
‣ then /lib
‣ & finally /usr/lib
• harvest the DT_NEEDED entries from the DSO
◦ check if the DT_NEEDED entry is already in _our_ link map
(ie have we loaded the library for some other reason already)
we do not consider entries in the default link map, or any other
private namespaces created by dlmopen().
◦ if we haven't, open it as for the original DSO above, and repeat.
◦ if we already have the DSO open, add its link map structure
to your list of link maps without opening it again.
• once we don't require any more DSOs (we've opened everything)
fix up the lookup tables using the link maps
For the basic use case of opening a DSO without exposing its symbols
to any other DSOs we already have this is sufficient. However in the
libcapsule case there's a new wrinkle - we want to open a DSO (and
most of its dependencies) from an external source. To give a concrete
example:
Consider an application inside a "runtime" (for our purposes, a mostly
self-contained set of DSOs, binaries and so forth separated from the main
system) which wants to use a library from the host OS (which is not
compatible with the set of DSOs in the runtime, hence libcapsule).
We have made the "real" set of libraries available under /host in the
runtime (that is, the / of the real system is mounted at /host in the
runtime, which has its own /).
If we naively dlmopen() a DSO from the /host tree, dlmopen will go
and find all the DT_NEEDED items required to satisfy it, but from
/ instead of from /host (since dlmopen knows nothing about /host):
Less than ideal, since in our special case we don't just need to isolate
one DSO from the rest, but two whole set of DSOs from one another. So what's
the solution?
The key lies in the algorithm presented above: Note that before opening a
DSO, we check to see if we already have it in our list of link maps: This
check is done against the ‘bare’ "libfoo.so.X" style name of the DSO, not
its full path.
If we manually (and recursively) harvest the list of DSOs from the DT_NEEDED
entries, and open them in reverse dependency order (ie we start with the
thing that has no dependencies, then the things that only needed that, and
so on and so forth) then the dlmopen() call won't go looking for them
elsewhere.
That's the theory - there are a few more details. For example:
We need to be careful when resolving symlinks since the filesystem we
are interested in is remapped to /host, not /, so absolute symlinks
will point to the ‘wrong’ place).
We must manually load the ld.so.cache from /host/etc/… and remap
all its entries to the right location under /host (same reason as
the symlink problem above).
But having said that, the basic method works. Success! We can control
the DSOs loaded to satisfy our target, and isolate them all in a
private namespace.
Controlling symbol visibility
----------------------------------------------------------------------------
Having succeeded in opening a DSO without exposing any of its symbols, we
now need to make sure the other DSOs (including the main program) use the
symbols from the DSO we _do_ want to expose.
The simplest (in that it requires the least knowledge of the details of
how a dynamically linked program works) approach would be to define, in
a proxy library, for each function we wish to export, a proxy function
with the same signature as its ‘real’ implementation, which could find
that address with dlsym() and re-dispatch the call there, then let our
program link against that (this last easily achieved by giving our proxy
library the same name as the ‘real’ one).
However, this has a few disadvantages:
• doesn't handle varargs functions
• requires knowledge of the signature of each function
◦ this makes it much harder to automate proxy generation
• mechanism cannot be extended to handle variables
• doubles the function call overhead for every call: we have to
call our proxy function, which then makes the real call
Ideally we'd like to find a different approach that has none of these
limitations. To do so we're going to have to examine, in greater detail,
how the "lookup tables" we've been talking about actually work.
At the heart of all this is something called a Global Offset Table,
or GOT (the name is possibly slightly misleading - it's not the table
that's global, but the offsets).
Each DSO contains a GOT, which consists of an array of entries, each
containing (after dynamic linking has completed) the real address of
a given function (or other object, but we're concerned with functions
for now).
Each DSO also contains a Procedure Linkage Table (NOTE: this is a
lie, it contains two, but we turn out to care about only one of them).
When an external function is called for the first time the following
happens:
→ The caller puts the function arguments on the stack.
the way in which it does so is determined by the ‘calling convention’,
a set of rules for passing arguments to and retrieving return values
from a function. Both DSOs involved in a call must agree on the
convention in order for this to work.
→ Jump to the PLT entry for the function
This is at a fixed offset, so the only thing we need to
know to find it is the base address (in memory) of the section of
the DSO in which the PLT resides.
→ The PLT entry points to an entry in the GOT.
The GOT is in a writable section of memory, but is of a fixed size
and has well defined entries of a fixed size also, so again, as long
as we know the base address, the PLT entry can always send us to
the right place.
→ The GOT entry contains a ‘relocation record’. There are many different
types of relocation record - fortunately we only care about one.
This relocation record consists of two or three values which can be used
to calculate the real address to which execution should jump.
Having calculated our jump, we transfer execution there.
Now the _first_ time we encounter a GOT entry, it actually points
to a special function which finds the _real_ function address,
SCRIBBLES IT BACK INTO THE RELOCATION RECORD, then jumps to the
function proper.
→ The function grabs the arguments from the stack, handles them,
pushes its return value (if any) onto the stack (as per the calling
convention), then passes control back to its caller.
→ the caller pulls the return value off the stack, and does something
with it (or not).
The _next_ time the function is called (from the same DSO), we will jump from
the GOT directly to the function, without hitting the special resolver.
First call: Subsequent calls:
┌───────┬──────────┐ ┌───────┬──────────┐
┌─┤ DSO A │ call foo │<───────┐ ┌─┤ DSO A │ call foo │<─┐
│ └───────┴──────────┘ │ │ └───────┴──────────┘ │
└>┌───────┬──────────┐ │ └>┌───────┬──────────┐ │
┌─┤ DSO A │ PLT: foo │ │ ┌─┤ DSO A │ PLT: foo │ │
│ └───────┴──────────┘ │ │ └───────┴──────────┘ │
└>┌───────┬─────────────────┐ │ └>┌───────┬──────────┐ │
┌─┤ DSO A │ GOT: <Resolver> │ │ ┌─┤ DSO A │ GOT: foo │ │
│ └───────┴───┬─────────────┘ │ │ └───────┴──────────┘ │
│ ↿ <foo> │ └>┌───────┬──────────┐ │
└>┌───────┬───┴──────┐ │ │ DSO B │ foo ├──┘
┌─┤ DSO A │ Resolver │ │ └───────┴──────────┘
│ └───────┴──────────┘ │
└>┌───────┬──────────┐ │
│ DSO B │ foo ├────────┘
└───────┴──────────┘
The key to where we jump is the relocation record in the GOT of DSO A
It's worth noting here that the only things that know the signature
(ie the argument and return types of foo) are the caller in DSO A and
foo itself: None of the intermediates know or care. This is promising,
as not caring about the signature is one of our goals.
An approach that should work, then, is as follows:
• Prepare a proxy library with the same name as the real DSO
• Arrange for said proxy to have a public function for each one
we wish to proxy (signature unimportant, since we will never
actually call these stubroutines)
• In our [proxy] library initialisation stage:
◦ walk the list of loaded DSOs
◦ locate the PLT entry for each function we wish to proxy
◦ fetch the address of the proxied function(s) using dlsym()
(this is the real address inside the private namespace)
◦ follow the PLT to the GOT relocation record (RR)
◦ scribble our real address into the GOT RR
From now on, in each DSO we've scribbled on, calls to proxied functions
will jump directly from its GOT to the real function in the private
namespace, bypassing the resolver stage (and bypassing our proxy library
entirely).
NOTE: The above is mostly true. There is the case of RELRO linking,
where the GOT:<Resolver> stage is handled early by the linker/loader,
resolving all function addresses whether or not they're ever called.
In RELRO linking the GOT memory page(s) are also mprotect()ed to read-only,
which would prevent us from scribbling on the GOT(s) in question, but
we can work around this by finding the relevant mprotect()ed pages and
toggling the write permission bit on them before we start (and flipping
the bit back when we're done).
We can only currently work around RELRO linking on Linux currently: I'm not
sure any other ELF systems expose the necessary mprotect meta data to us.
<!--
Copyright © 2017 Collabora Ltd
This file is part of libcapsule.
libcapsule is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation; either version 2.1 of the
License, or (at your option) any later version.
libcapsule is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with libcapsule. If not, see <http://www.gnu.org/licenses/>.
-->
<refentry id="capsule-init-project">
<refentryinfo>
<title>capsule-init-project</title>
<productname>libcapsule</productname>
<authorgroup>
<author>
<contrib>Developer</contrib>
<firstname>Vivek</firstname>
<surname>Das Mohapatra</surname>
</author>
<author>
<contrib>Developer</contrib>
<firstname>Simon</firstname>
<surname>McVittie</surname>
</author>
</authorgroup>
</refentryinfo>
<refmeta>
<refentrytitle>capsule-init-project</refentrytitle>
<manvolnum>1</manvolnum>
<refmiscinfo class="manual">User Commands</refmiscinfo>
</refmeta>
<refnamediv>
<refname>capsule-init-project</refname>
<refpurpose>libcapsule proxy library project setup tool</refpurpose>
</refnamediv>
<refsynopsisdiv>
<cmdsynopsis>
<command>capsule-init-project</command>
<arg choice="opt">OPTIONS</arg>
<arg choice="req" rep="repeat">TARGET</arg>
</cmdsynopsis>
</refsynopsisdiv>
<refsect1>
<title>Description</title>
<para>
<command>capsule-init-project</command> creates a project which
uses libcapsule to create a proxy for a library, usually from
a foreign filesystem tree.
</para>
</refsect1>
<refsect1>
<title>Arguments</title>
<variablelist>
<varlistentry>
<term><option>TARGET</option></term>
<listitem>
<para>
The base name of the target, of the form libFOO.so.X (eg libz.so.1).
It can optionally be combined with a version number in the
form libFOO.so.X/VERSION (e.g. libz.so.1/1.2.3).
</para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>Options</title>
<variablelist>
<varlistentry>
<term><option>--capsule-pkgdatadir=PATH</option></term>
<listitem>
<para>Use supporting files from PATH</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>--capsule-symbols-tool=PATH</option></term>
<listitem>
<para>Use replacement capsule-symbols(1)</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>--capsule-version-tool=PATH</option></term>
<listitem>
<para>Use replacement capsule-version(1)</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>--search-tree=PATH</option></term>
<listitem>
<para>
Find libraries to be proxied in this chroot,
sysroot or container at compile-time.
</para>
<para>default: TREE or /host if unset</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>--set-version=VERSION</option></term>
<listitem>
<para>
Use this as the package version
(major, major.minor or major.minor.micro)
instead of using capsule-version(1) on the first
<option>TARGET</option>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>--symbols-from-dir=PATH</option></term>
<listitem>
<para>
Use symbols files in this directory instead of the
output of capsule-symbols(1)
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>--runtime-tree=PATH</option></term>
<listitem>
<para>
Find libraries to be proxied in this chroot, sysroot or
container at runtime. The default is /host.
</para>
<para>
If libcapsule was compiled with glibc 2.17 or later and the
process is not privileged, this can be overridden at runtime
by setting a SONAME-specific environment variable (for
example CAPSULE_LIBGL_SO_1_PREFIX for libGL.so.1) or by
setting the generic CAPSULE_PREFIX environment variable.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>--package-name=PACKAGE</option></term>
<listitem>
<para>
Use this name for the generated Autotools package,
instead of libFOO-proxy
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>--destination=PATH</option></term>
<listitem>
<para>
Use this name for the generated directory,
instead of libFOO-proxy or the argument of
<option>--package-name</option>
</para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1><title>See also</title>
<para>
<citerefentry>
<refentrytitle>capsule-mkstublib</refentrytitle>
<manvolnum>1</manvolnum>
</citerefentry>
</para>
</refsect1>
</refentry>
<!--
Copyright © 2017 Collabora Ltd
This file is part of libcapsule.
libcapsule is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation; either version 2.1 of the
License, or (at your option) any later version.
libcapsule is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with libcapsule. If not, see <http://www.gnu.org/licenses/>.
-->
<refentry id="capsule-mkstublib">
<refentryinfo>
<title>capsule-mkstublib</title>
<productname>libcapsule</productname>
<authorgroup>
<author>
<contrib>Developer</contrib>
<firstname>Vivek</firstname>
<surname>Das Mohapatra</surname>
</author>
<author>
<contrib>Developer</contrib>
<firstname>Simon</firstname>
<surname>McVittie</surname>
</author>
</authorgroup>
</refentryinfo>
<refmeta>
<refentrytitle>capsule-mkstublib</refentrytitle>
<manvolnum>1</manvolnum>
<refmiscinfo class="manual">User Commands</refmiscinfo>
</refmeta>
<refnamediv>
<refname>capsule-mkstublib</refname>
<refpurpose>
Command used by the libcapsule build system to generate proxy
library source files.
</refpurpose>
</refnamediv>
<refsynopsisdiv>
<cmdsynopsis>
<command>capsule-mkstublib</command>
<arg choice="opt">OPTIONS</arg>
<arg choice="plain">TARGET</arg>
<arg choice="plain">EXCLUDES</arg>
<arg choice="plain">EXPORTS</arg>
<arg choice="plain">OUTPUT</arg>
<arg choice="opt">DSO-VERSION<arg choice="opt">TREE</arg></arg>
</cmdsynopsis>
</refsynopsisdiv>
<refsect1>
<title>Description</title>
<para>
<command>capsule-mkstublib</command> generates the source code
for a libcapsule proxy library from a standard set of inputs
(described below).
</para>
</refsect1>
<refsect1>
<title>Arguments</title>
<variablelist>
<varlistentry>
<term><option>TARGET</option></term>
<listitem>
<para>
The SONAME of the target, of the form libFOO.so.X (eg libz.so.1)
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>EXCLUDES</option></term>
<listitem>
<para>
A file containing a list of SONAMEs (one on each line) not to
include in the libcapsule proxy: DSOs listed here will not
be loaded from the foreign tree and must come from the
normal set searched by the linker.
</para>
<para>
For example if libz.so.1 is listed here, and TARGET depends
on libz.so.1 then it will be run-time linked against the
copy of libz from / - not any copies which are found under TREE
</para>
<para>
This file is empty by default in new prjects.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>EXPORTS</option></term>
<listitem>
<para>
A file containing a list of SONAMEs (one on each line) whose
symbols should be exported.
</para>
<para>Symbols from TARGET are always exported.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>OUTPUT</option></term>
<listitem>
<para>
Output filename
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>DSO-VERSION</option></term>
<listitem>
<para>
The version of the target library our proxy will pretend to be,
in the format MAJOR:MINOR:SUB
</para>
<para>
The format is the same format as consumed by libtool.
Only MAJOR must be present if this argument is supplied.
</para>
<para>
The default value is determined by parsing the soname of the
library.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>TREE</option></term>
<listitem>
<para>
The mount point of the foreign filesystem tree from which TARGET
and its dependencies will be acquired.
</para>
<para>
This value can be overridden by --runtime-tree and --search-tree.
</para>
<para>
The default is the soname-specific environment variable (eg
CAPSULE_LIBGL_SO_1_PREFIX for libGL.so.1), or the CAPSULE_PREFIX
environment variable, or /host. The environment variables are
ignored if the process is privileged, or if libcapsule was
compiled with glibc older than 2.17.
</para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>Options</title>
<variablelist>
<varlistentry>
<term><option>--capsule-symbols-tool=PATH</option></term>
<listitem>
<para>Use replacement capsule-symbols(1)</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>--symbols-from=PATH</option></term>
<listitem>
<para>
Use this symbols file instead of the output of capsule-symbols(1)
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>--[no]-update-symbols</option></term>
<listitem>
<para>
Do or don't update the exported symbol list if EXPORTS is
updated [default: do]
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>--search-tree=PATH</option></term>
<listitem>
<para>
Find libraries to be proxied in this chroot,
sysroot or container at compile-time.
</para>
<para>default: TREE or / if unset</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>--runtime-tree=PATH</option></term>
<listitem>
<para>
Find libraries to be proxied in this chroot, sysroot or
container at runtime. The default is /host.
</para>
<para>
If libcapsule was compiled with glibc 2.17 or later and the
process is not privileged, this can be overridden at runtime
by setting a SONAME-specific environment variable (for
example CAPSULE_LIBGL_SO_1_PREFIX for libGL.so.1) or by
setting the generic CAPSULE_PREFIX environment variable.
</para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>Bugs</title>
<para>
The order of arguments is a bit pathological: This is for
historical reasons. Since the command is not expected to be
invoked outside of libcapsule's build scripts this is not
considered a major problem.
</para>
</refsect1>
<refsect1>
<title>See also</title>
<para>
<citerefentry>
<refentrytitle>capsule-init-project</refentrytitle>
<manvolnum>1</manvolnum>
</citerefentry>
</para>
</refsect1>
</refentry>
<!--
Copyright © 2017 Collabora Ltd
This file is part of libcapsule.
libcapsule is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation; either version 2.1 of the
License, or (at your option) any later version.
libcapsule is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with libcapsule. If not, see <http://www.gnu.org/licenses/>.
-->
<xsl:stylesheet version = '1.0'
xmlns:xi="http://www.w3.org/2003/XInclude"
xmlns:xsl='http://www.w3.org/1999/XSL/Transform'
xmlns:saxon="http://icl.com/saxon"
xmlns:xslt="http://xml.apache.org/xslt"
xmlns:string="http://exslt.org/strings"
xmlns:ext="http://exslt.org/common"
extension-element-prefixes="saxon"
exclude-result-prefixes="xi">
<xsl:strip-space elements="*" />
<xsl:output omit-xml-declaration="yes"
indent="yes"
encoding="utf-8"
xslt:indent-amount="2"/>
<xsl:template match="node()|@*" mode="description">
<xsl:apply-templates/>
</xsl:template>
<xsl:template name="paramdesc" match="refsect2[@role='function']"
mode="paramdesc">
<xsl:param name="matched" select="indexterm/primary"/>
<xsl:if test="$matched = $target">
<xsl:element name="title">Parameters:</xsl:element>
<xsl:element name="variablelist">
<xsl:for-each select="refsect3[@role='parameters']//row">
<xsl:element name="varlistentry">
<xsl:element name="term">
<xsl:element name="code">
<xsl:value-of select="concat(entry[@role='parameter_name'], ': ')"/>
</xsl:element>
</xsl:element>
<xsl:element name="listitem">
<xsl:element name="para">
<xsl:value-of select="entry[@role='parameter_description']"/>
</xsl:element>
</xsl:element>
</xsl:element>
</xsl:for-each>
</xsl:element>
</xsl:if>
</xsl:template>
<xsl:template name="retdesc" match="refsect2[@role='function']"
mode="retdesc">
<xsl:param name="matched" select="indexterm/primary"/>
<xsl:if test="$matched = $target">
<xsl:for-each select="refsect3[@role='returns']/*">
<xsl:copy-of select="."/>
</xsl:for-each>
</xsl:if>
</xsl:template>
<!-- //////////////////////////////////////////////////////// -->
<xsl:template match="node()|@*" name="ignore">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="entry[@role='function_name']/link" name="refnamediv">
<xsl:param name="matched" select="."/>
<xsl:if test="$matched = $target">
<xsl:element name="refname">
<xsl:value-of select="."/>
</xsl:element>
<xsl:apply-templates/>
</xsl:if>
</xsl:template>
<xsl:template match="refsynopsisdiv/synopsis/link" mode="refnamediv">
<xsl:param name="matched" select="."/>
<xsl:if test="$matched = $target">
<xsl:element name="refname">
<xsl:value-of select="."/>
</xsl:element>
<xsl:apply-templates/>
</xsl:if>
</xsl:template>
<xsl:template name="paramdef" match="parameter" mode="funcsig">
<xsl:param name="tok" select="string:tokenize(., ' ')"/>
<xsl:param name="last" select="ext:node-set($tok)[last()]"/>
<xsl:param name="name" select="string:tokenize($last, '*')"/>
<xsl:param name="stars" select="substring-before($last, $name)"/>
<xsl:element name="paramdef">
<xsl:for-each select="ext:node-set($tok)[position() != last()]">
<xsl:value-of select="concat(., ' ')"/>
</xsl:for-each>
<xsl:value-of select="$stars"/>
<xsl:element name="parameter">
<xsl:value-of select="$name"/>
</xsl:element>
</xsl:element>
</xsl:template>
<xsl:template name="funcproto" match="refsect2[@role='function']">
<xsl:param name="matched" select="indexterm/primary"/>
<xsl:if test="$matched = $target">
<xsl:element name="funcprototype">
<xsl:element name="funcdef">
<xsl:value-of
select="concat(substring-before(programlisting,'&#xa;'), ' ')"/>
<xsl:element name="function">
<xsl:value-of select="indexterm/primary"/>
</xsl:element>
</xsl:element>
<xsl:apply-templates select="programlisting" mode="funcsig"/>
</xsl:element>
</xsl:if>
</xsl:template>
<xsl:template name="voiddesc" match="refsect2[@role='function']"
mode="voiddesc">
<xsl:param name="matched" select="indexterm/primary"/>
<xsl:if test="$matched = $target">
<xsl:for-each select="para">
<xsl:copy-of select="."/>
</xsl:for-each>
</xsl:if>
</xsl:template>
<xsl:template match="/refentry" name="top">
<xsl:element name="refentry">
<xsl:attribute name="id"><xsl:value-of select="@id"/></xsl:attribute>
<xsl:element name="refentryinfo">
<xsl:element name="productname">libcapsule</xsl:element>
<xsl:element name="authorgroup">
<xsl:element name="contrib">Author</xsl:element>
<xsl:element name="firstname">Vivek</xsl:element>
<xsl:element name="surname">Das Mohapatra</xsl:element>
</xsl:element>
<xsl:element name="authorgroup">
<xsl:element name="contrib">Author</xsl:element>
<xsl:element name="firstname">Simon</xsl:element>
<xsl:element name="surname">McVittie</xsl:element>
</xsl:element>
</xsl:element>
<xsl:element name="refmeta">
<xsl:element name="refentrytitle">
<!-- xsl:value-of select="/refentry/refmeta/refentrytitle"/ -->
<xsl:value-of select="$target"/>
</xsl:element>
<xsl:element name="manvolnum">
<xsl:value-of select="/refentry/refmeta/manvolnum"/>
</xsl:element>
<xsl:element name="refmiscinfo">
<xsl:attribute name="class">manual</xsl:attribute>
<xsl:value-of select="normalize-space(refmeta/refmiscinfo)"/>
</xsl:element>
</xsl:element>
<xsl:element name="refnamediv">
<xsl:choose>
<xsl:when test="refsect1[@role='functions_proto']">
<xsl:apply-templates select="refsect1[@role='functions_proto']"/>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="refsynopsisdiv[@role='synopsis']" mode="refnamediv"/>
</xsl:otherwise>
</xsl:choose>
</xsl:element>
<xsl:element name="refsynopsisdiv">
<xsl:element name="funcsynopsis">
<xsl:element name="funcsynopsisinfo">
<xsl:value-of select="$fsinfo"/>
</xsl:element>
</xsl:element>
<xsl:apply-templates select="refsect1[@role='details']"/>
</xsl:element>
<xsl:element name="refsect1">
<xsl:element name="title">Description:</xsl:element>
<xsl:apply-templates
select="refsect1[@role='details' and contains(@id,'functions_details')]/refsect2"
mode="voiddesc"/>
<xsl:element name="refsect2">
<xsl:apply-templates
select="refsect1[@role='details' and contains(@id,'functions_details')]/refsect2"
mode="paramdesc"/>
</xsl:element>
<xsl:element name="refsect2">
<xsl:apply-templates
select="refsect1[@role='details' and contains(@id,'functions_details')]/refsect2"
mode="retdesc"/>
</xsl:element>
</xsl:element>
<xsl:element name="refsect1">
<xsl:element name="title">See Also:</xsl:element>
<xsl:element name="para">
<xsl:for-each select="refsect1[@role='details']/refsect2[@role='function']/indexterm/primary">
<xsl:element name="link">
<xsl:element name="function">
<xsl:value-of select="concat(.,'(3)')"/>
</xsl:element>
</xsl:element>
<xsl:choose>
<xsl:when test="position() != last()">
<xsl:text>, </xsl:text>
</xsl:when>
</xsl:choose>
</xsl:for-each>
</xsl:element>
</xsl:element>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
# Copyright © 2017 Collabora Ltd
# This file is part of libcapsule.
# libcapsule is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as
# published by the Free Software Foundation; either version 2.1 of the
# License, or (at your option) any later version.
# libcapsule is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
# You should have received a copy of the GNU Lesser General Public
# License along with libcapsule. If not, see <http://www.gnu.org/licenses/>.
#
# ============================================================================
# standalone man pages from docbook source:
XSLTPROC_FLAGS = \
--nonet \
--stringparam man.output.quietly 1 \
--stringparam funcsynopsis.style ansi \
--stringparam man.th.extra1.suppress 1 \
--stringparam man.authors.section.enabled 1 \
--stringparam man.copyright.section.enabled 0
XSLT_DOMAIN = docbook.sourceforge.net
XSLT_MAN = http://$(XSLT_DOMAIN)/release/xsl/current/manpages/docbook.xsl
XSLT_CAPARGS = --stringparam fsinfo "$$(printf "\#define _GNU_SOURCE\012\#include <capsule/capsule.h>")" --stringparam target
XSLTPROC_STD = $(XSLTPROC) $(XSLTPROC_FLAGS)
man_MANS =
if HAVE_XSLTPROC
%.1: doc/%.xml
$(AM_V_GEN) $(XSLTPROC_STD) $(XSLT_MAN) $<
man_MANS += capsule-init-project.1 capsule-mkstublib.1
endif # HAVE_XSLTPROC
if ENABLE_GTK_DOC
xml/capsule.xml: docs
%.3.xml: xml/capsule.xml doc/devhelp2man.xslt documentation.mk
$(AM_V_GEN) $(XSLTPROC_STD) $(XSLT_CAPARGS) $* $(srcdir)/doc/devhelp2man.xslt $< > $@
%.3: %.3.xml documentation.mk
$(AM_V_GEN) $(XSLTPROC_STD) $(XSLT_MAN) $<
man_MANS += capsule_init.3
man_MANS += capsule_shim_dlopen.3
man_MANS += capsule_external_dlsym.3
endif # ENABLE_GTK_DOC
CLEANFILES += $(man_MANS)