Den 2010-01-28 21:08 skrev Ralf Wildenhues:
* Peter Rosin wrote on Thu, Jan 28, 2010 at 09:06:10AM CET:
The test fails for me when Libtool is configured with --disable-shared.
I'm not sure that failure is specific to this test, whether we need to
fix it before committing the test or so; looking at this is probably
prudent.
Not sure how to proceed... When I added -dlopen module.la to the link
of the main program and a LTDL_SET_PRELOADED_SYMBOLS invocation it
*almost* works.
These changes should be made in the test.
Ok, done.
But the test still fails since it isn't possible to add
a custom loader before the preopen loader. I get this diff in the
expected output when running the program:
@@ -6,7 +6,6 @@
first_sym (first): first_ctx
result: first_symbol
first_close (first): first_ctx
-first_open denies a request
result: module_symbol
first_open denies a request
last_open ("last"): last_ctx
I.e. the "first" loader doesn't see any request regarding opening
of module.la. Come to think of it, it only sees the request to open
the actual shared library when the preopen loader isn't involved,
and since that step don't happen with preopened modules the
behaviour is not that surprising...
The test clearly expects too much from the current implementation, but I
kinda think you should be able to override the preopen loader as well.
So, how to weaken^Wfix the test?
What about just tossing the "real" module and settle for checking that
a prepended loader is in front of an appended loader?
Well, if the idea of allowing a user-provided shared module loader was
that it should be possible to extend libltdl like this on systems for
which libltdl doesn't natively provide shared module opening facilities,
and that doesn't work, then that's a failure, no? OTOH, the user
shouldn't use --disable-shared on those other systems, so our emulation
is not perfect with this case; I'm thinking we should thus either let
the test fail or skip in this case.
I don't know why the user-provided shared module loader API was added,
but I do know that the only user of the mechanism that I found in a
cursory search on the Internet (pulseaudio) uses it to wrap an existing
loader in order to do some extra book-keeping. That will not work in
the static case as it isn't possible to get in before the preopen
loader.
Anyway, I added a skip if there is no shared module built.
Adding loaders before the preopen loader is probably problematic for
other reasons.
I'm fine with your other nits to my diff.
I'm unsure if that means that I should push it, so I'm attaching
what I have. Just say the magic word and I'll push :-)
Tested on debian and wine/mingw32/debian both with and without
CC=g++ and both with and without --disable-shared.
Cheers,
Peter
2010-01-29 Peter Rosin <p...@lysator.liu.se>
Ralf Wildenhues <ralf.wildenh...@gmx.de>
Testsuite exposure for dlloader API.
* tests/dlloader-api.at: New file, new test.
* Makefile.am (TESTSUITE_AT): Update.
diff --git a/Makefile.am b/Makefile.am
index 40a0138..29a639a 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -485,6 +485,7 @@ TESTSUITE_AT = tests/testsuite.at \
tests/lt_dlopen_a.at \
tests/lt_dlopenext.at \
tests/ltdl-api.at \
+ tests/dlloader-api.at \
tests/loadlibrary.at \
tests/lalib-syntax.at \
tests/resident.at \
diff --git a/tests/dlloader-api.at b/tests/dlloader-api.at
new file mode 100644
index 0000000..a9aa814
--- /dev/null
+++ b/tests/dlloader-api.at
@@ -0,0 +1,418 @@
+# dlloader.at -- test dlloader functionality -*- Autotest -*-
+#
+# Copyright (C) 2010 Free Software Foundation, Inc.
+# This file is part of GNU Libtool.
+#
+# GNU Libtool is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# GNU Libtool 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Libtool; see the file COPYING. If not, a copy
+# can be downloaded from http://www.gnu.org/licenses/gpl.html,
+# or obtained by writing to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+####
+
+AT_SETUP([dlloader API])
+AT_KEYWORDS([libltdl])
+
+AT_DATA([main.c],
+[[#include <ltdl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static int
+first_init (lt_user_data data)
+{
+ const char *ctx = (const char *) data;
+
+ printf ("first_init: %s\n", ctx);
+
+ return 0;
+}
+
+static lt_module
+first_open (lt_user_data data, const char *filename, lt_dladvise advise)
+{
+ static const char *first_module = "first";
+ const char *ctx = (const char *) data;
+
+ if (!filename || strcmp (filename, "first"))
+ {
+ printf ("first_open denies a request\n");
+ lt_dlseterror (LT_ERROR_FILE_NOT_FOUND);
+ return NULL;
+ }
+
+ printf ("first_open (\"%s\"): %s\n", filename, ctx);
+
+ return (lt_module) first_module;
+}
+
+static const char *
+first_symbol (void)
+{
+ return "first_symbol";
+}
+
+static void *
+first_sym (lt_user_data data, lt_module module, const char *symbolname)
+{
+ const char *ctx = (const char *) data;
+ const char *filename = (const char *) module;
+
+ printf ("first_sym (%s): %s\n", filename, ctx);
+
+ return (void *) first_symbol;
+}
+
+static int
+first_close (lt_user_data data, lt_module module)
+{
+ const char *ctx = (const char *) data;
+ const char *filename = (const char *) module;
+
+ printf ("first_close (%s): %s\n", filename, ctx);
+
+ return 0;
+}
+
+static int
+first_exit (lt_user_data data)
+{
+ const char *ctx = (const char *) data;
+
+ printf ("first_exit: %s\n", ctx);
+
+ return 0;
+}
+
+static int
+last_init (lt_user_data data)
+{
+ const char *ctx = (const char *) data;
+
+ printf ("last_init: %s\n", ctx);
+
+ return 0;
+}
+
+static lt_module
+last_open (lt_user_data data, const char *filename, lt_dladvise advise)
+{
+ static const char *last_module = "last";
+ const char *ctx = (const char *) data;
+
+ if (!filename || strcmp (filename, "last"))
+ {
+ printf ("last_open denies a request\n");
+ lt_dlseterror (LT_ERROR_FILE_NOT_FOUND);
+ return NULL;
+ }
+
+ printf ("last_open (\"%s\"): %s\n", filename, ctx);
+
+ return (lt_module) last_module;
+}
+
+static const char *
+last_symbol (void)
+{
+ return "last_symbol";
+}
+
+static void *
+last_sym (lt_user_data data, lt_module module, const char *symbolname)
+{
+ const char *ctx = (const char *) data;
+ const char *filename = (const char *) module;
+
+ printf ("last_sym (%s): %s\n", filename, ctx);
+
+ return (void *) last_symbol;
+}
+
+static int
+last_close (lt_user_data data, lt_module module)
+{
+ const char *ctx = (const char *) data;
+ const char *filename = (const char *) module;
+
+ printf ("last_close (%s): %s\n", filename, ctx);
+
+ return 0;
+}
+
+static int
+last_exit (lt_user_data data)
+{
+ const char *ctx = (const char *) data;
+
+ printf ("last_exit: %s\n", ctx);
+
+ return 0;
+}
+
+typedef const char *module_func (void);
+
+int
+main (int argc, char* argv[])
+{
+ int err = 0;
+ lt_dlvtable *first;
+ lt_dlvtable *last;
+ lt_dlhandle module = NULL;
+ module_func *symbol;
+ const char *first_ctx = "first_ctx";
+ const char *last_ctx = "last_ctx";
+ const lt_dlvtable *finder;
+
+ LTDL_SET_PRELOADED_SYMBOLS ();
+
+ if (lt_dlinit ())
+ {
+ printf ("lt_dlinit failed\n");
+ return 1;
+ }
+
+ first = (lt_dlvtable *) malloc (sizeof (*first));
+ if (!first)
+ {
+ printf ("malloc failed\n");
+ err = 1;
+ goto cleanup;
+ }
+
+ first->name = "first";
+ first->sym_prefix = NULL;
+ first->module_open = first_open;
+ first->module_close = first_close;
+ first->find_sym = first_sym;
+ first->dlloader_init = first_init; /* test that it isn't called twice */
+ first->dlloader_exit = first_exit;
+ first->dlloader_data = (lt_user_data) first_ctx;
+ first->priority = LT_DLLOADER_PREPEND;
+
+ if (first_init (first->dlloader_data))
+ {
+ printf ("first_init failed\n");
+ err = 1;
+ goto cleanup;
+ }
+
+ if (lt_dlloader_add (first))
+ {
+ printf ("lt_dlloader_add failed: %s\n", lt_dlerror ());
+ err = 1;
+ goto cleanup;
+ }
+
+ finder = lt_dlloader_find ("first");
+
+ if (!finder)
+ {
+ printf ("lt_dlloader_find failed: %s\n", lt_dlerror ());
+ err = 1;
+ goto cleanup;
+ }
+
+ printf ("Found loader \"%s\"\n", finder->name);
+
+ last = (lt_dlvtable *) malloc (sizeof (*last));
+ if (!last)
+ {
+ printf ("malloc failed\n");
+ err = 1;
+ goto cleanup;
+ }
+
+ last->name = "last";
+ last->sym_prefix = NULL;
+ last->module_open = last_open;
+ last->module_close = last_close;
+ last->find_sym = last_sym;
+ last->dlloader_init = last_init; /* test that it isn't called twice */
+ last->dlloader_exit = last_exit;
+ last->dlloader_data = (lt_user_data) last_ctx;
+ last->priority = LT_DLLOADER_APPEND;
+
+ if (last_init (last->dlloader_data))
+ {
+ printf ("last_init failed\n");
+ err = 1;
+ goto cleanup;
+ }
+
+ if (lt_dlloader_add (last))
+ {
+ printf ("lt_dlloader_add failed: %s\n", lt_dlerror ());
+ err = 1;
+ goto cleanup;
+ }
+
+ finder = lt_dlloader_find ("last");
+
+ if (!finder)
+ {
+ printf ("lt_dlloader_find failed: %s\n", lt_dlerror ());
+ err = 1;
+ goto cleanup;
+ }
+
+ printf ("Found loader \"%s\"\n", finder->name);
+
+ module = lt_dlopen ("first");
+
+ if (!module)
+ {
+ printf ("lt_dlopen failed: %s\n", lt_dlerror ());
+ err = 1;
+ goto cleanup;
+ }
+
+ symbol = (module_func *) lt_dlsym (module, "symbol");
+
+ if (!symbol)
+ {
+ printf ("lt_dlsym failed: %s\n", lt_dlerror ());
+ err = 1;
+ goto cleanup;
+ }
+
+ printf ("result: %s\n", symbol ());
+
+ lt_dlclose (module);
+ module = lt_dlopen ("./module.la");
+
+ if (!module)
+ {
+ printf ("lt_dlopen failed: %s\n", lt_dlerror ());
+ err = 1;
+ goto cleanup;
+ }
+
+ symbol = (module_func *) lt_dlsym (module, "symbol");
+
+ if (!symbol)
+ {
+ printf ("lt_dlsym failed: %s\n", lt_dlerror ());
+ err = 1;
+ goto cleanup;
+ }
+
+ printf ("result: %s\n", symbol ());
+
+ lt_dlclose (module);
+ module = lt_dlopen ("last");
+
+ if (!module)
+ {
+ printf ("lt_dlopen failed: %s\n", lt_dlerror ());
+ err = 1;
+ goto cleanup;
+ }
+
+ symbol = (module_func *) lt_dlsym (module, "symbol");
+
+ if (!symbol)
+ {
+ printf ("lt_dlsym failed: %s\n", lt_dlerror ());
+ err = 1;
+ goto cleanup;
+ }
+
+ printf ("result: %s\n", symbol ());
+
+ if (lt_dlopen ("no-module"))
+ {
+ printf ("lt_dlopen unexpectedly opened \"no-module\"\n");
+ err = 1;
+ goto cleanup;
+ }
+
+ if (lt_dlloader_remove ("first") != first)
+ {
+ printf ("vtable of first loader has changed\n");
+ err = 1;
+ goto cleanup;
+ }
+
+ free (first);
+
+cleanup:
+ if (module)
+ {
+ lt_dlclose (module);
+ }
+ lt_dlexit ();
+ return err;
+}
+]])
+
+AT_DATA([module.c],
+[[
+#ifdef __cplusplus
+extern "C"
+#endif
+const char *symbol (void);
+const char *
+symbol (void)
+{
+ return "module_symbol";
+}
+]])
+
+LT_AT_HOST_DATA(expout,
+[[first_init: first_ctx
+Found loader "first"
+last_init: last_ctx
+Found loader "last"
+first_open ("first"): first_ctx
+first_sym (first): first_ctx
+result: first_symbol
+first_close (first): first_ctx
+first_open denies a request
+result: module_symbol
+first_open denies a request
+last_open ("last"): last_ctx
+last_sym (last): last_ctx
+result: last_symbol
+first_open denies a request
+last_open denies a request
+first_exit: first_ctx
+last_close (last): last_ctx
+last_exit: last_ctx
+]])
+
+: ${LTDLINCL="-I$abs_top_srcdir/libltdl"}
+: ${LIBLTDL="$abs_builddir/../libltdl/libltdlc.la"}
+
+CPPFLAGS="$LTDLINCL $CPPFLAGS"
+
+AT_CHECK([$LIBTOOL --mode=compile $CC $CPPFLAGS $CFLAGS -c module.c],
+ [], [ignore], [ignore])
+AT_CHECK([$LIBTOOL --mode=link $CC $CFLAGS $LDFLAGS -o module.la ]dnl
+ [-rpath /nowhere -module -avoid-version -no-undefined ]dnl
+ [module.lo],
+ [], [ignore], [ignore])
+
+dnl Not possible to override the preopen loader, so skip if not shared.
+. ./module.la
+AT_CHECK([test -n "$dlname" || (exit 77)])
+
+AT_CHECK([$CC $CPPFLAGS $CFLAGS -c main.c], [], [ignore], [ignore])
+AT_CHECK([$LIBTOOL --mode=link $CC $CFLAGS $LDFLAGS -o main$EXEEXT ]dnl
+ [main.$OBJEXT -dlopen module.la $LIBLTDL],
+ [], [ignore], [ignore])
+
+LT_AT_EXEC_CHECK([./main], [], [expout], [ignore], [])
+
+AT_CLEANUP