diff --git a/.gitignore b/.gitignore index ab8670fcbfd6fa60aaf931dc38029b852e97271e..1868f0b877f2c74b8feb9b81edc2f29f8cfa0d6b 100644 --- a/.gitignore +++ b/.gitignore @@ -60,4 +60,5 @@ libcapsule-*.txt *.prerequisites *.signals !/build-aux/git-version-gen +!/build-aux/tap-test.sh !/m4/ax_is_release.m4 diff --git a/Makefile.am b/Makefile.am index c5d39930a2337099fe2ac69c23d75a16e9417c47..c5370a1501d547a73537c0782d597577c9ff49c2 100644 --- a/Makefile.am +++ b/Makefile.am @@ -92,8 +92,7 @@ dist_pkgdata_DATA = data/capsule-shim.h \ data/capsule-shim.mk.in \ disabled.mk -BUILT_SOURCES = $(shim_srcs) -BUILT_SOURCES += $(top_srcdir)/.version +BUILT_SOURCES = $(top_srcdir)/.version $(top_srcdir)/.version: $(AM_V_GEN)echo $(VERSION) > $@-t && mv $@-t $@ @@ -105,6 +104,127 @@ dist-hook-git-version-gen: include $(top_srcdir)/disabled.mk +# ============================================================================ +# GNOME-style installed-tests + +insttestsdir = $(libexecdir)/installed-tests/$(PACKAGE_TARNAME) + +# /!\ Order is important here: the helper library must come first +nobase_insttests_LTLIBRARIES = tests/red/libhelper.la \ + tests/green/libhelper.la \ + tests/lib/libhelper.la \ + tests/red/libnotgl.la \ + tests/green/libnotgl.la \ + tests/lib/libnotgl.la \ + tests/shim/libnotgl.la +# Install the source code so we can rebuild it inside a container if we want to +nobase_dist_insttests_DATA = tests/libtest.sh \ + tests/notgl.h \ + tests/notgl-green.c \ + tests/notgl-red.c \ + tests/notgl-ref.c \ + tests/notgl-helper.h \ + tests/notgl-helper-green.c \ + tests/notgl-helper-red.c \ + tests/notgl-helper-ref.c \ + tests/shim/libnotgl.so.c.dlopen \ + tests/shim/libnotgl.so.c.dlsym \ + tests/shim/libnotgl.so.c.excluded \ + tests/shim/libnotgl.so.c.shared \ + tests/shim/libnotgl.so.c.symbols + +tests_lib_libnotgl_la_SOURCES = tests/notgl-ref.c \ + tests/notgl.h \ + tests/notgl-helper.h +tests_lib_libnotgl_la_LDFLAGS = -shared -version-number 0:42:23 +tests_lib_libnotgl_la_LIBADD = tests/lib/libhelper.la + +tests_red_libnotgl_la_SOURCES = tests/notgl-red.c \ + tests/notgl.h \ + tests/notgl-helper.h +# Give it a gratuitously higher version number +tests_red_libnotgl_la_LDFLAGS = -shared -version-number 0:123:456 +# We want the RUNPATH to point to tests/lib here, so link to that helper +tests_red_libnotgl_la_LIBADD = tests/lib/libhelper.la + +tests_green_libnotgl_la_SOURCES = tests/notgl-green.c \ + tests/notgl.h \ + tests/notgl-helper.h +# Give this one a gratuitously *lower* version number +tests_green_libnotgl_la_LDFLAGS = -shared -version-number 0:23:42 +# Again, we want the RUNPATH to point to tests/lib here, so link to that helper +tests_green_libnotgl_la_LIBADD = tests/lib/libhelper.la + +tests_lib_libhelper_la_SOURCES = tests/notgl-helper-ref.c \ + tests/notgl-helper.h +tests_lib_libhelper_la_LDFLAGS = -shared -version-number 0:42:23 + +tests_red_libhelper_la_SOURCES = tests/notgl-helper-red.c \ + tests/notgl-helper.h +tests_red_libhelper_la_LDFLAGS = -shared -version-number 0:123:456 + +tests_green_libhelper_la_SOURCES = tests/notgl-helper-green.c \ + tests/notgl-helper.h +tests_green_libhelper_la_LDFLAGS = -shared -version-number 0:23:42 + +nodist_tests_shim_libnotgl_la_SOURCES = tests/shim/libnotgl.so.c +tests_shim_libnotgl_la_LIBADD = libcapsule.la +tests_shim_libnotgl_la_LDFLAGS = -shared -version-number 0:0:0 +tests_shim_libnotgl_la_CFLAGS = $(AM_CFLAGS) -I$(top_srcdir)/capsule + +tests/shim/lib%.so.c: tests/shim/lib%.so.c.excluded tests/shim/lib%.so.c.dlopen tests/shim/lib%.so.c.dlsym tests/shim/lib%.so.c.shared tests/shim/lib%.so.c.symbols data/capsule-mkstublib Makefile + $(AM_V_GEN)\ + PKG_CONFIG_PATH=$(abs_builddir)/data \ + V=$V \ + $(top_srcdir)/data/capsule-mkstublib \ + --dlopen-implementation=$(srcdir)/$@.dlopen \ + --dlsym-implementation=$(srcdir)/$@.dlsym \ + --symbols-from=$(srcdir)/$@.symbols \ + --no-update-symbols \ + --runtime-tree=/host \ + $$(basename $@ .c).0 \ + $(srcdir)/$@.excluded \ + $(srcdir)/$@.shared \ + $@ + +LOG_DRIVER = env AM_TAP_AWK='$(AWK)' \ + $(SHELL) $(top_srcdir)/build-aux/tap-driver.sh +LOG_COMPILER = $(top_srcdir)/build-aux/tap-test.sh +TEST_EXTENSIONS = .sh +SH_LOG_DRIVER = $(LOG_DRIVER) +SH_LOG_COMPILER = $(LOG_COMPILER) +AM_TESTS_ENVIRONMENT = export CAPSULE_TESTS_UNINSTALLED=1; \ + export G_TEST_SRCDIR="$(abs_srcdir)"; \ + export G_TEST_BUILDDIR="$(abs_builddir)";\ + export G_DEBUG=gc-friendly; \ + export MALLOC_CHECK_=2; +test_extra_programs = tests/notgl-user \ + tests/notgl-helper-user +tests_notgl_user_LDADD = tests/lib/libnotgl.la +tests_notgl_helper_user_LDADD = tests/lib/libnotgl.la \ + tests/lib/libhelper.la +test_extra_scripts = + +test_programs = +test_scripts = tests/notgl.sh +nobase_insttests_PROGRAMS = $(test_programs) \ + $(test_extra_programs) +nobase_dist_insttests_SCRIPTS = $(test_scripts) \ + $(test_extra_scripts) +TESTS = $(test_programs) \ + $(test_scripts) +testmetadir = $(datadir)/installed-tests/$(PACKAGE_TARNAME) +testmeta_DATA = $(patsubst %,%.test,$(test_programs) $(test_scripts)) +$(testmeta_DATA): tests/%.test: tests/% Makefile + @$(MKDIR_P) $(dir $@) + $(AM_V_GEN)set -e; \ + (\ + echo "[Test]"; \ + echo "Type=session"; \ + echo "Output=TAP"; \ + echo "Exec=$(insttestsdir)/tests/$* --tap"; \ + ) > $@.tmp && mv $@.tmp $@ + # ============================================================================ # gtk-doc configuration: see /usr/share/doc/gtk-doc-tools/examples/Makefile.am DOC_MODULE = libcapsule @@ -126,13 +246,12 @@ GTKDOC_CFLAGS = GTKDOC_LIBS = include $(top_srcdir)/gtk-doc.make -# ============================================================================ -# CLEANFILES is unconditionally set by gtk-doc.make, have to do these after: -CLEANFILES += $(shim_files) $(shim_srcs) -# ============================================================================ # standalone man pages include $(top_srcdir)/documentation.mk -# This needs to come after we include gtk-doc.make, which unconditionally -# defines it +# These need to come after we include gtk-doc.make, which unconditionally +# defines these variables +CLEANFILES += $(testmeta_DATA) +CLEANFILES += tests/shim/libnotgl.so.c EXTRA_DIST += $(top_srcdir)/.version +EXTRA_DIST += build-aux/tap-test.sh diff --git a/build-aux/tap-test.sh b/build-aux/tap-test.sh new file mode 100755 index 0000000000000000000000000000000000000000..67858ebcf363b7eb701d259bed0074c383d52ac4 --- /dev/null +++ b/build-aux/tap-test.sh @@ -0,0 +1,13 @@ +#!/bin/sh +# Wrapper to make GTest tests output TAP syntax, because Automake's test +# drivers do not currently support passing the same command-line argument +# to each test executable. All GTest tests produce TAP output if invoked +# with the --tap option. +# +# Usage: "tap-test.sh test-foo --verbose ..." is equivalent to +# "test-foo --tap --verbose ..." + +set -e +t="$1" +shift +exec "$t" --tap "$@" diff --git a/configure.ac b/configure.ac index 69cfc5fc540a372853e50550470e31e128d1101a..875aa62d8b5fba6e27907f265a67d0a51a66747f 100644 --- a/configure.ac +++ b/configure.ac @@ -22,6 +22,7 @@ AC_INIT([libcapsule], [], [], [https://gitlab.collabora.com/vivek/libcapsule]) AC_CONFIG_AUX_DIR([build-aux]) AC_CONFIG_MACRO_DIR([m4]) +AC_REQUIRE_AUX_FILE([tap-driver.sh]) m4_pattern_forbid([^AX_], [Please install GNU autoconf-archive]) diff --git a/debian/control b/debian/control index e73fd1acec2f95753aebf5e96f28886030ca7455..0cd4ffeb216af62345e6041bed3e4a186722ef9a 100644 --- a/debian/control +++ b/debian/control @@ -7,6 +7,7 @@ Build-Depends: autoconf, autoconf-archive (>= 20160916-1), automake, + bubblewrap, debhelper, dh-autoreconf, gtk-doc-tools, @@ -49,6 +50,21 @@ Description: . This package contains the files needed to generate libcapsule proxy libraries. +Package: libcapsule-tests +Architecture: amd64 i386 +Section: misc +Priority: optional +Depends: + bubblewrap, + ${shlibs:Depends}, +Description: + libcapsule is a helper library used to implement segregated run-time + dynamic linking proxy libraries - used (for example) to load a library + that has dependencies incompatible with the regular libraries that are + part of the host OS, such as an incompatible libstdc++ version. + . + This package contains automated tests. + Package: libcapsule0 Architecture: amd64 i386 Multi-Arch: same diff --git a/debian/libcapsule-tests.install b/debian/libcapsule-tests.install new file mode 100644 index 0000000000000000000000000000000000000000..142caa69c1d08d0ce9fe0a6a020d5ec42688a115 --- /dev/null +++ b/debian/libcapsule-tests.install @@ -0,0 +1,2 @@ +usr/lib/*/capsule/installed-tests/libcapsule +usr/share/installed-tests/libcapsule diff --git a/debian/rules b/debian/rules index 1008db081d18eed745f695f76b4c614a763c0642..cab626a4f571068520d5e29a59d6bf76a8eea5da 100755 --- a/debian/rules +++ b/debian/rules @@ -12,6 +12,7 @@ override_dh_auto_configure: override_dh_install: rm -f debian/tmp/usr/lib/*/*.la + find debian/tmp/usr/lib/*/capsule/installed-tests -name '*.la' -print -delete dh_install --fail-missing override_dh_autoreconf: diff --git a/debian/tests/control b/debian/tests/control index bb7544f170938511b5c8076632f51f19f74440e9..2b70beb5c046e2cc81b0af7b534a3dee64eaddb5 100644 --- a/debian/tests/control +++ b/debian/tests/control @@ -2,3 +2,8 @@ Tests: smoke Depends: build-essential, libcapsule-dev, + +Tests: gnome-desktop-testing +Depends: + gnome-desktop-testing, + libcapsule-tests, diff --git a/debian/tests/gnome-desktop-testing b/debian/tests/gnome-desktop-testing new file mode 100755 index 0000000000000000000000000000000000000000..2958be2dab55e801a2c51efa85e0fe4added2c6c --- /dev/null +++ b/debian/tests/gnome-desktop-testing @@ -0,0 +1,5 @@ +#!/bin/sh + +set -e +exec 2>&1 +exec gnome-desktop-testing-runner libcapsule diff --git a/tests/libtest.sh b/tests/libtest.sh new file mode 100644 index 0000000000000000000000000000000000000000..f81601c5d3894a9dde7d8d5592a4565e28e1f453 --- /dev/null +++ b/tests/libtest.sh @@ -0,0 +1,119 @@ +# vim:set ft=sh sts=4 sw=4 et: + +# 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/>. + +test_tempdir="$(mktemp -d /tmp/libcapsule.XXXXXXXX)" +trap 'rm -fr --one-file-system $test_tempdir' EXIT +mkdir "$test_tempdir/host" +export CAPSULE_PREFIX="$test_tempdir/host" + +test_num=0 +any_failed=0 + +skip_all () { + echo "1..0 # SKIP - $*" + exit 0 +} + +pass () { + test_num=$((test_num + 1)) + echo "ok $test_num - $*" +} + +fail () { + test_num=$((test_num + 1)) + echo "not ok $test_num - $*" + any_failed=1 +} + +skip () { + test_num=$((test_num + 1)) + echo "ok $test_num # SKIP - $*" +} + +ok () { + local condition="$1" + shift + + if $condition; then + pass "$*" + else + fail "$*" + fi +} + +is () { + local got="$1" + local expected="$2" + shift 2 + + if [ "x$got" = "x$expected" ]; then + pass "$* ($got)" + else + echo "# Got: $got" + echo "# Expected: $expected" + fail "$* ($got != $expected)" + fi +} + +isnt () { + local got="$1" + local unexpected="$2" + shift 2 + + if [ "x$got" != "x$unexpected" ]; then + echo "# Got: $got" + echo "# Expected: anything but $unexpected" + fail "$* (expected anything but $unexpected)" + else + pass "$* ($got)" + fi +} + +exec_is () { + local command="$1" + local expected_status="$2" + local expected="$3" + local status=0 + shift 3 + + got="$(eval "$command")" || status="$?" + + if [ "x$status" != "x$expected_status" ]; then + fail "$* (status $status != $expected_status)" + fi + + if [ "x$got" = "x$expected" ]; then + pass "$* ($got)" + else + echo "# Got: $got" + echo "# Expected: $expected" + fail "$* ($got != $expected)" + fi +} + +run_verbose () { + echo "# \$($*)..." + "$@" +} + +done_testing () { + echo "# End of tests" + echo "1..$test_num" + exit $any_failed +} diff --git a/tests/notgl-green.c b/tests/notgl-green.c new file mode 100644 index 0000000000000000000000000000000000000000..ec7d1bb1edb017370e0e0b82dde7754d04379a4c --- /dev/null +++ b/tests/notgl-green.c @@ -0,0 +1,49 @@ +// Copyright © 2017 Collabora Ltd + +// notgl-green — one of two implementations of libnotgl, taking the +// role of the NVIDIA implementation of OpenGL + +// 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/>. + +#include "notgl.h" + +#include <dlfcn.h> + +#include "notgl-helper.h" + +const char * +notgl_get_implementation( void ) +{ + return "green"; +} + +const char * +notgl_extension_both( void ) +{ + return "green implementation of common extension"; +} + +const char * +notgl_extension_green( void ) +{ + return "green-only extension"; +} + +const char * +notgl_use_helper( void ) +{ + return helper_get_implementation(); +} diff --git a/tests/notgl-helper-green.c b/tests/notgl-helper-green.c new file mode 100644 index 0000000000000000000000000000000000000000..0cfd2c99adb7d9319bb7ba8e0572f1d768c2322d --- /dev/null +++ b/tests/notgl-helper-green.c @@ -0,0 +1,27 @@ +// Copyright © 2017 Collabora Ltd + +// notgl-helper-green — An implementation of libnotgl-helper in the +// host, taking the role of the host's libstdc++ + +// 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/>. + +#include "notgl-helper.h" + +const char * +helper_get_implementation( void ) +{ + return "host (green)"; +} diff --git a/tests/notgl-helper-red.c b/tests/notgl-helper-red.c new file mode 100644 index 0000000000000000000000000000000000000000..c0da1ee910ddb3bc9bbe3e0f70368bc2bd8aeef4 --- /dev/null +++ b/tests/notgl-helper-red.c @@ -0,0 +1,27 @@ +// Copyright © 2017 Collabora Ltd + +// notgl-helper-red — An implementation of libnotgl-helper in the +// host, taking the role of the host's libstdc++ + +// 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/>. + +#include "notgl-helper.h" + +const char * +helper_get_implementation( void ) +{ + return "host (red)"; +} diff --git a/tests/notgl-helper-ref.c b/tests/notgl-helper-ref.c new file mode 100644 index 0000000000000000000000000000000000000000..29557c6c31e1cb72a0d90643352657f2cec37f6e --- /dev/null +++ b/tests/notgl-helper-ref.c @@ -0,0 +1,27 @@ +// Copyright © 2017 Collabora Ltd + +// notgl-helper-ref — The implementation of libnotgl-helper in the +// container, taking the role of the container's libstdc++ + +// 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/>. + +#include "notgl-helper.h" + +const char * +helper_get_implementation( void ) +{ + return "container (reference)"; +} diff --git a/tests/notgl-helper-user.c b/tests/notgl-helper-user.c new file mode 100644 index 0000000000000000000000000000000000000000..f6362b0dd376686b75a3f9025980c042c57d5b8e --- /dev/null +++ b/tests/notgl-helper-user.c @@ -0,0 +1,64 @@ +// 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/>. + +#include <dlfcn.h> +#include <stdio.h> +#include <stdlib.h> + +#include "notgl.h" +#include "notgl-helper.h" + +static notgl_extension_function +get_extension( const char *name ) +{ + return dlsym( RTLD_DEFAULT, name ); +} + +int +main ( int argc, + char **argv ) +{ + notgl_extension_function f; + + printf( "NotGL implementation: %s\n", notgl_get_implementation() ); + printf( "NotGL helper implementation: %s\n", notgl_use_helper() ); + + f = get_extension( "notgl_extension_both" ); + + if( f ) + printf( "notgl_extension_both: %s\n", f() ); + else + printf( "notgl_extension_both: (not found)\n" ); + + f = get_extension( "notgl_extension_red" ); + + if( f ) + printf( "notgl_extension_red: %s\n", f() ); + else + printf( "notgl_extension_red: (not found)\n" ); + + f = get_extension( "notgl_extension_green" ); + + if( f ) + printf( "notgl_extension_green: %s\n", f() ); + else + printf( "notgl_extension_green: (not found)\n" ); + + printf( "NotGL helper implementation as seen by executable: %s\n", helper_get_implementation () ); + + return 0; +} diff --git a/tests/notgl-helper.h b/tests/notgl-helper.h new file mode 100644 index 0000000000000000000000000000000000000000..2c622dc457a45235c5abc02f336f80eba51dad31 --- /dev/null +++ b/tests/notgl-helper.h @@ -0,0 +1,26 @@ +// Copyright © 2017 Collabora Ltd + +// libnotgl-helper — A library used by the OpenGL driver, taking the +// role of libstdc++ + +// 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/>. + +#pragma once + +#define HELPER_PUBLIC __attribute__((visibility("default"))) + +HELPER_PUBLIC +const char *helper_get_implementation( void ); diff --git a/tests/notgl-red.c b/tests/notgl-red.c new file mode 100644 index 0000000000000000000000000000000000000000..090f7187510ce3b4d8a337e1f4138b7bbd6dba1c --- /dev/null +++ b/tests/notgl-red.c @@ -0,0 +1,49 @@ +// Copyright © 2017 Collabora Ltd + +// notgl-red — one of two implementations of libnotgl, taking the +// role of the AMD implementation of OpenGL + +// 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/>. + +#include "notgl.h" + +#include <dlfcn.h> + +#include "notgl-helper.h" + +const char * +notgl_get_implementation( void ) +{ + return "red"; +} + +const char * +notgl_extension_both( void ) +{ + return "red implementation of common extension"; +} + +const char * +notgl_extension_red( void ) +{ + return "red-only extension"; +} + +const char * +notgl_use_helper( void ) +{ + return helper_get_implementation (); +} diff --git a/tests/notgl-ref.c b/tests/notgl-ref.c new file mode 100644 index 0000000000000000000000000000000000000000..a1c7993bed9d2663caf6d6e7be26a19e79e7fc05 --- /dev/null +++ b/tests/notgl-ref.c @@ -0,0 +1,43 @@ +// Copyright © 2017 Collabora Ltd + +// notgl-ref — reference implementation of libnotgl, taking the +// role of the (possibly outdated) implementation of OpenGL in the container + +// 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/>. + +#include "notgl.h" + +#include <dlfcn.h> + +#include "notgl-helper.h" + +const char * +notgl_get_implementation( void ) +{ + return "reference"; +} + +const char * +notgl_extension_both( void ) +{ + return "reference implementation of common extension"; +} + +const char * +notgl_use_helper( void ) +{ + return helper_get_implementation (); +} diff --git a/tests/notgl-user.c b/tests/notgl-user.c new file mode 100644 index 0000000000000000000000000000000000000000..5abc05497f6fa253836d5e5d0e1b6c1f27414942 --- /dev/null +++ b/tests/notgl-user.c @@ -0,0 +1,61 @@ +// 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/>. + +#include <dlfcn.h> +#include <stdio.h> +#include <stdlib.h> + +#include "notgl.h" + +static notgl_extension_function +get_extension( const char *name ) +{ + return dlsym( RTLD_DEFAULT, name ); +} + +int +main ( int argc, + char **argv ) +{ + notgl_extension_function f; + + printf( "NotGL implementation: %s\n", notgl_get_implementation() ); + printf( "NotGL helper implementation: %s\n", notgl_use_helper() ); + + f = get_extension( "notgl_extension_both" ); + + if( f ) + printf( "notgl_extension_both: %s\n", f() ); + else + printf( "notgl_extension_both: (not found)\n" ); + + f = get_extension( "notgl_extension_red" ); + + if( f ) + printf( "notgl_extension_red: %s\n", f() ); + else + printf( "notgl_extension_red: (not found)\n" ); + + f = get_extension( "notgl_extension_green" ); + + if( f ) + printf( "notgl_extension_green: %s\n", f() ); + else + printf( "notgl_extension_green: (not found)\n" ); + + return 0; +} diff --git a/tests/notgl.h b/tests/notgl.h new file mode 100644 index 0000000000000000000000000000000000000000..42b84d5f196ad66fd830b62ee48e03c50a5b8855 --- /dev/null +++ b/tests/notgl.h @@ -0,0 +1,35 @@ +// Copyright © 2017 Collabora Ltd + +// notgl — a library not entirely unlike OpenGL + +// 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/>. + +#pragma once + +#define NOTGL_PUBLIC __attribute__((visibility("default"))) + +typedef const char *(*notgl_extension_function)( void ); + +NOTGL_PUBLIC +const char *notgl_get_implementation( void ); +NOTGL_PUBLIC +const char *notgl_extension_both( void ); +NOTGL_PUBLIC +const char *notgl_extension_red( void ); +NOTGL_PUBLIC +const char *notgl_extension_green( void ); +NOTGL_PUBLIC +const char *notgl_use_helper( void ); diff --git a/tests/notgl.sh b/tests/notgl.sh new file mode 100755 index 0000000000000000000000000000000000000000..225772315c02ab2fa03c4b48c655c41f62864188 --- /dev/null +++ b/tests/notgl.sh @@ -0,0 +1,171 @@ +#!/bin/bash + +# 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/>. + +set -eu -o pipefail + +. "$(dirname "$0")"/libtest.sh + +if ! bwrap --ro-bind / / true; then + skip_all "1..0 # SKIP - cannot run bwrap" +fi + +: ${G_TEST_SRCDIR:="$(cd "$(dirname "$0")"/..; pwd)"} +: ${G_TEST_BUILDDIR:="$(cd "$(dirname "$0")"/..; pwd)"} + +echo "# Source or installation directory: $G_TEST_SRCDIR" +echo "# Build or installation directory: $G_TEST_BUILDDIR" + +if [ -n "${CAPSULE_TESTS_UNINSTALLED:-}" ]; then + echo "# Running uninstalled: yes" + # We need to bypass libtool because it plays around with + # LD_LIBRARY_PATH, and so do we. + libs=/.libs + notgl_user="$("$G_TEST_BUILDDIR/libtool" --mode=execute ls -1 "$G_TEST_BUILDDIR/tests/notgl-user")" + notgl_helper_user="$("$G_TEST_BUILDDIR/libtool" --mode=execute ls -1 "$G_TEST_BUILDDIR/tests/notgl-helper-user")" +else + echo "# Running uninstalled: no" + libs= + notgl_user="$G_TEST_BUILDDIR/tests/notgl-user" + notgl_helper_user="$G_TEST_BUILDDIR/tests/notgl-helper-user" +fi + +echo +echo "# Without special measures:" +run_verbose env LD_LIBRARY_PATH="$G_TEST_BUILDDIR/tests/lib$libs" "$notgl_user" > "$test_tempdir/output" +sed -e 's/^/# /' "$test_tempdir/output" +exec_is \ + 'sed -ne "s/^NotGL implementation: //p" $test_tempdir/output' \ + 0 reference +exec_is \ + 'sed -ne "s/^NotGL helper implementation: //p" $test_tempdir/output' \ + 0 "container (reference)" +exec_is \ + 'sed -ne "s/^notgl_extension_both: //p" $test_tempdir/output' \ + 0 "reference implementation of common extension" +exec_is \ + 'sed -ne "s/^notgl_extension_red: //p" $test_tempdir/output' \ + 0 "(not found)" +exec_is \ + 'sed -ne "s/^notgl_extension_green: //p" $test_tempdir/output' \ + 0 "(not found)" + +echo +run_verbose env LD_LIBRARY_PATH="$G_TEST_BUILDDIR/tests/lib$libs" "$notgl_helper_user" > "$test_tempdir/output" +sed -e 's/^/# /' "$test_tempdir/output" +exec_is \ + 'sed -ne "s/^NotGL implementation: //p" $test_tempdir/output' \ + 0 reference +exec_is \ + 'sed -ne "s/^NotGL helper implementation: //p" $test_tempdir/output' \ + 0 "container (reference)" +exec_is \ + 'sed -ne "s/^notgl_extension_both: //p" $test_tempdir/output' \ + 0 "reference implementation of common extension" +exec_is \ + 'sed -ne "s/^notgl_extension_red: //p" $test_tempdir/output' \ + 0 "(not found)" +exec_is \ + 'sed -ne "s/^NotGL helper implementation as seen by executable: //p" $test_tempdir/output' \ + 0 "container (reference)" + +echo +echo "# With libcapsule:" +# We mount the "host system" on $test_tempdir/host. +# +# In the "container", the shim libnotgl is picked up from tests/shim because +# it was prepended to the LD_LIBRARY_PATH. The helper library used by +# libnotgl, libhelper, is picked up from tests/lib as usual. +# +# In the "host system", there is a tmpfs over the build or installation +# directory to avoid tests/shim being found *again*, and the "red" +# implementations of libnotgl and libhelper is mounted over tests/lib. +run_verbose bwrap \ + --ro-bind / / \ + --dev-bind /dev /dev \ + --ro-bind / "$CAPSULE_PREFIX" \ + --tmpfs "$CAPSULE_PREFIX$G_TEST_BUILDDIR" \ + --ro-bind "$G_TEST_BUILDDIR/tests/red" "$CAPSULE_PREFIX$G_TEST_BUILDDIR/tests/lib" \ + --setenv LD_LIBRARY_PATH "$G_TEST_BUILDDIR/tests/shim$libs:$G_TEST_BUILDDIR/tests/lib$libs" \ + "$notgl_user" > "$test_tempdir/output" +sed -e 's/^/# /' "$test_tempdir/output" +# Functions from libnotgl get dispatched through the shim to the "red" +# implementation from the "host system". This mirrors functions from libGL +# being dispatched through the shim to the AMD implementation of libGL. +exec_is \ + 'sed -ne "s/^NotGL implementation: //p" $test_tempdir/output' \ + 0 red +# When the "red" implementation of libnotgl calls functions from libhelper, +# implementation from the "host system". This mirrors functions from +# libstdc++ that are called by the host libGL ending up in the host libstdc++. +exec_is \ + 'sed -ne "s/^NotGL helper implementation: //p" $test_tempdir/output' \ + 0 "host (red)" +# We can dlsym() for an implemementation of an extension that is part of +# the ABI of the shim and the reference implementation. +exec_is \ + 'sed -ne "s/^notgl_extension_both: //p" $test_tempdir/output' \ + 0 "red implementation of common extension" +# We can also dlsym() for an implemementation of an extension that is only +# available in the "red" implementation. +exec_is \ + 'sed -ne "s/^notgl_extension_red: //p" $test_tempdir/output' \ + 0 "red-only extension" +exec_is \ + 'sed -ne "s/^notgl_extension_green: //p" $test_tempdir/output' \ + 0 "(not found)" + +echo +# Similar to the above, but now the host system is using the "green" +# implementation of libnotgl, mirroring the NVIDIA implementation of libGL. +run_verbose bwrap \ + --ro-bind / / \ + --dev-bind /dev /dev \ + --ro-bind / "$CAPSULE_PREFIX" \ + --tmpfs "$CAPSULE_PREFIX$G_TEST_BUILDDIR" \ + --ro-bind "$G_TEST_BUILDDIR/tests/green" "$CAPSULE_PREFIX$G_TEST_BUILDDIR/tests/lib" \ + --setenv LD_LIBRARY_PATH "$G_TEST_BUILDDIR/tests/shim$libs:$G_TEST_BUILDDIR/tests/lib$libs" \ + "$notgl_helper_user" > "$test_tempdir/output" +sed -e 's/^/# /' "$test_tempdir/output" +exec_is \ + 'sed -ne "s/^NotGL implementation: //p" $test_tempdir/output' \ + 0 green +exec_is \ + 'sed -ne "s/^NotGL helper implementation: //p" $test_tempdir/output' \ + 0 "host (green)" +exec_is \ + 'sed -ne "s/^notgl_extension_both: //p" $test_tempdir/output' \ + 0 "green implementation of common extension" +exec_is \ + 'sed -ne "s/^notgl_extension_red: //p" $test_tempdir/output' \ + 0 "(not found)" +exec_is \ + 'sed -ne "s/^notgl_extension_green: //p" $test_tempdir/output' \ + 0 "green-only extension" +# Also, this program is linked directly to libhelper, mirroring a program +# that is linked directly to libstdc++ in the libGL case. It sees the +# container's libhelper, not the host's - even though libnotgl sees the +# host's libhelper when it looks up the same symbol. (This is the point +# of libcapsule.) +exec_is \ + 'sed -ne "s/^NotGL helper implementation as seen by executable: //p" $test_tempdir/output' \ + 0 "container (reference)" + +done_testing + +# vim:set sw=4 sts=4 et: diff --git a/tests/shim/libnotgl.so.c.dlopen b/tests/shim/libnotgl.so.c.dlopen new file mode 100644 index 0000000000000000000000000000000000000000..3fdfdf1fd56734a318e6c4f529fdf358b0c79c13 --- /dev/null +++ b/tests/shim/libnotgl.so.c.dlopen @@ -0,0 +1,11 @@ +static void *_dlopen (const char *filename, int flag) +{ + if( flag & RTLD_GLOBAL ) + { + fprintf( stderr, "Warning: libcapsule dlopen wrapper cannot pass " + "RTLD_GLOBAL to underlying dlmopen(%s...) call\n", + filename ); + flag = (flag & ~RTLD_GLOBAL) & 0xfffff; + } + return capsule_shim_dlopen( symbol_ns, prefix, exclude, filename, flag ); +} diff --git a/tests/shim/libnotgl.so.c.dlsym b/tests/shim/libnotgl.so.c.dlsym new file mode 100644 index 0000000000000000000000000000000000000000..62d13bae5be190ceb857dc88e7d562b5f5b73f19 --- /dev/null +++ b/tests/shim/libnotgl.so.c.dlsym @@ -0,0 +1,12 @@ +// This allows symbols inside the capsule to be found by dlopen calls from +// outside the capsule iff they are in one of the exported DSOs. +// +// This is useful in libGL shims as libGL has an ‘interesting’ history +// of symbols appearing and disappearing so its users often do a +// bizarre dlopen()/dlsym() dance instead of referring to a symbol +// directly (and we may be missing those symbols from our static +// export list even if the target libGL has them) +static void *_dlsym (void *handle, const char *symbol) +{ + return capsule_shim_dlsym( dso, handle, symbol, valid_dlsym_sources ); +} diff --git a/tests/shim/libnotgl.so.c.excluded b/tests/shim/libnotgl.so.c.excluded new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/tests/shim/libnotgl.so.c.shared b/tests/shim/libnotgl.so.c.shared new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/tests/shim/libnotgl.so.c.symbols b/tests/shim/libnotgl.so.c.symbols new file mode 100644 index 0000000000000000000000000000000000000000..338681e486b56f67aff9b164aa9fb254081217e3 --- /dev/null +++ b/tests/shim/libnotgl.so.c.symbols @@ -0,0 +1,2 @@ +notgl_get_implementation +notgl_use_helper