Stephen Gran schrieb: > Thank you for this comprehensive review and investigation of the > problem. This is roughly what we arrived at as well. Sadly, the best > place for this to be fixed is in ltdl, and a request has been filed with > them to add a function to call dlopen with RTDL_GLOBAL. There is not > much we can do now except wait (or use the bundled copy of libltdl in > the freeradius source, which feels wrong to me as a distribution choice).
I still think the best way to fix it would be to have shared library dependencies in the dynamic perl extension libs, i.e. perl extensions like Dumper.so should depend on libperl.so.x.y themselves. One thing I don't know yet is if this would break other programs embedding perl statically via libperl.a. I will try to find out later. To build my own freeradius-perl package providing a dynamic FreeRADIUS rlm_perl that works on Debian, I've figured out the following workaround: let rlm_perl dlopen(libperl.x.y, RTLD_GLOBAL) at module initialization time to make the symbols of libperl.x.y globally visible. Actually, libperl.x.y has already indirectly been loaded by lt_dlopen(rlm_perl), but the symbols are not globally visible due to the Debian libltdl change avoiding namespace pollution. The workaround tries to detect if rlm_perl is built using a Debian perl and then, if perl reports a dynamic libperl, adds code to dlopen() the correct libperl.so.x.y. The decision could be overridden at configuration time: > --enable-libperl-workaround[=LIB] > which libperl to dlopen() on Debian GNU/Linux > systems if required [check] I'll attach the patch to this bug report for your consideration. Enrik
? src/modules/rlm_perl/autom4te.cache ? src/modules/rlm_perl/configure.cvs Index: src/modules/rlm_perl/Makefile.in =================================================================== RCS file: /source/radiusd/src/modules/rlm_perl/Makefile.in,v retrieving revision 1.4 diff -u -r1.4 Makefile.in --- src/modules/rlm_perl/Makefile.in 22 Jan 2006 21:46:41 -0000 1.4 +++ src/modules/rlm_perl/Makefile.in 8 Jul 2007 06:27:25 -0000 @@ -5,6 +5,7 @@ TARGET = @targetname@ SRCS = rlm_perl.c HEADERS = +PERL = @PERL@ RLM_CFLAGS = @perl_cflags@ RLM_LIBS = @perl_ldflags@ RLM_INSTALL = install-scripts Index: src/modules/rlm_perl/config.h.in =================================================================== RCS file: /source/radiusd/src/modules/rlm_perl/config.h.in,v retrieving revision 1.2 diff -u -r1.2 config.h.in --- src/modules/rlm_perl/config.h.in 29 Dec 2004 05:09:05 -0000 1.2 +++ src/modules/rlm_perl/config.h.in 8 Jul 2007 06:27:25 -0000 @@ -14,3 +14,6 @@ /* Define to the version of this package. */ #undef PACKAGE_VERSION + +/* Debian GNU/Linux workaround */ +#undef DEBIAN_DLOPEN_LIBPERL Index: src/modules/rlm_perl/configure =================================================================== RCS file: /source/radiusd/src/modules/rlm_perl/configure,v retrieving revision 1.6 diff -u -r1.6 configure --- src/modules/rlm_perl/configure 6 Jul 2007 12:25:46 -0000 1.6 +++ src/modules/rlm_perl/configure 8 Jul 2007 06:27:26 -0000 @@ -1,5 +1,5 @@ #! /bin/sh -# From configure.in Revision: 1.3 . +# From configure.in Revision: 1.4 . # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.61. # @@ -1204,6 +1204,19 @@ cat <<\_ACEOF +Optional Features: + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --enable-libperl-workaround[=LIB] + which libperl to dlopen() on Debian GNU/Linux + systems if required [check] + +Optional Packages: + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --with-perl-binary[=perlbinary] + which perl binary to use for option detection [perl] + Some influential environment variables: CC C compiler command CFLAGS C compiler flags @@ -2792,8 +2805,32 @@ - # Extract the first word of "perl", so it can be a program name with args. -set dummy perl; ac_word=$2 +# Check whether --with-perl-binary was given. +if test "${with_perl_binary+set}" = set; then + withval=$with_perl_binary; case "$withval" in + yes) + rlm_perl_perl=perl ;; + *) + rlm_perl_perl="$withval" ;; + esac +else + rlm_perl_perl=perl + +fi + + + # Check whether --enable-libperl-workaround was given. +if test "${enable_libperl_workaround+set}" = set; then + enableval=$enable_libperl_workaround; rlm_perl_debian_libperl="$enableval" +else + rlm_perl_debian_libperl=yes + +fi + + + + # Extract the first word of "$rlm_perl_perl", so it can be a program name with args. +set dummy $rlm_perl_perl; ac_word=$2 { echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } if test "${ac_cv_prog_PERL+set}" = set; then @@ -2809,7 +2846,7 @@ test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then - ac_cv_prog_PERL="yes" + ac_cv_prog_PERL="$rlm_perl_perl" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi @@ -2834,7 +2871,7 @@ fail=$fail" perl" else old_CFLAGS=$CFLAGS - CFLAGS="$CFLAGS `perl -MExtUtils::Embed -e ccopts`" + CFLAGS="$CFLAGS `$PERL -MExtUtils::Embed -e ccopts`" smart_try_dir= @@ -3037,7 +3074,7 @@ fi if test "x$ac_cv_header_EXTERN_h" = "xyes"; then - perl_cflags='`perl -MExtUtils::Embed -e ccopts`' + perl_cflags='`$(PERL) -MExtUtils::Embed -e ccopts`' else fail="$fail EXTERN.h" targetname= @@ -3242,14 +3279,14 @@ fi if test "x$ac_cv_header_perl_h" = "xyes"; then - perl_cflags='`perl -MExtUtils::Embed -e ccopts`' + perl_cflags='`$(PERL) -MExtUtils::Embed -e ccopts`' else fail="$fail perl.h" targetname= fi old_LIBS="$LIBS" - LIBS="$old_LIBS `perl -MExtUtils::Embed -e ldopts`" + LIBS="$old_LIBS `$PERL -MExtUtils::Embed -e ldopts`" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF @@ -3295,13 +3332,41 @@ conftest$ac_exeext conftest.$ac_ext if test "x$BROKEN" = "x"; then - perl_ldflags='`perl -MExtUtils::Embed -e ldopts`' + perl_ldflags='`$(PERL) -MExtUtils::Embed -e ldopts`' else fail="$fail libperl.so" targetname= fi CFLAGS=$old_CFLAGS + + if test "x$fail" = "x" ; then + if perl -MExtUtils::Embed -e ccopts | grep DEBIAN > /dev/null ; then + { echo "$as_me:$LINENO: checking for Debian GNU/Linux libperl.so workaround" >&5 +echo $ECHO_N "checking for Debian GNU/Linux libperl.so workaround... $ECHO_C" >&6; } + if test "x$rlm_perl_debian_libperl" = "xyes" ; then + # autodetect libperl and remove minor version + eval `$PERL -V:libperl` + rlm_perl_debian_libperl=${libperl%.[0-9]*} + fi + case $rlm_perl_debian_libperl in + # accept anything looking like a shared library + *libperl.so*) + cat >>confdefs.h <<_ACEOF +#define DEBIAN_DLOPEN_LIBPERL "$rlm_perl_debian_libperl" +_ACEOF + + rlm_perl_debian_libperl="will dlopen($rlm_perl_debian_libperl, RTLD_GLOBAL)" + ;; + *) + rlm_perl_debian_libperl=no + ;; + esac + { echo "$as_me:$LINENO: result: $rlm_perl_debian_libperl" >&5 +echo "${ECHO_T}$rlm_perl_debian_libperl" >&6; } + fi + fi + fi targetname=rlm_perl Index: src/modules/rlm_perl/configure.in =================================================================== RCS file: /source/radiusd/src/modules/rlm_perl/configure.in,v retrieving revision 1.4 diff -u -r1.4 configure.in --- src/modules/rlm_perl/configure.in 6 Jul 2007 12:25:46 -0000 1.4 +++ src/modules/rlm_perl/configure.in 8 Jul 2007 06:27:26 -0000 @@ -8,21 +8,42 @@ AC_PROG_CC AC_PROG_CPP + dnl extra argument: --with-perl + AC_ARG_WITH([perl-binary], + [AS_HELP_STRING([--with-perl-binary@<:@=perlbinary@:>@], + [which perl binary to use for option detection @<:@perl@:>@])], + [case "$withval" in + yes) + rlm_perl_perl=perl ;; + *) + rlm_perl_perl="$withval" ;; + esac], + [rlm_perl_perl=perl] + ) + + dnl extra argument: --enable-libperl-workaround + AC_ARG_ENABLE([libperl-workaround], + [AS_HELP_STRING([--enable-libperl-workaround@<:@=LIB@:>@], + [which libperl to dlopen() on Debian GNU/Linux systems if required @<:@check@:>@])], + [rlm_perl_debian_libperl="$enableval"], + [rlm_perl_debian_libperl=yes] + ) + dnl put configuration checks here. dnl set $fail to what's missing, on fatal errors. dnl use AC_MSG_WARN() on important messages. - AC_CHECK_PROG(PERL, perl, yes, no) + AC_CHECK_PROG(PERL, $rlm_perl_perl, $rlm_perl_perl, no) if test "$PERL" = "no"; then fail=$fail" perl" else old_CFLAGS=$CFLAGS - CFLAGS="$CFLAGS `perl -MExtUtils::Embed -e ccopts`" + CFLAGS="$CFLAGS `$PERL -MExtUtils::Embed -e ccopts`" smart_try_dir= FR_SMART_CHECK_INCLUDE(EXTERN.h) if test "x$ac_cv_header_EXTERN_h" = "xyes"; then - perl_cflags='`perl -MExtUtils::Embed -e ccopts`' + perl_cflags='`$(PERL) -MExtUtils::Embed -e ccopts`' else fail="$fail EXTERN.h" targetname= @@ -30,27 +51,50 @@ FR_SMART_CHECK_INCLUDE(perl.h, [#include <EXTERN.h>]) if test "x$ac_cv_header_perl_h" = "xyes"; then - perl_cflags='`perl -MExtUtils::Embed -e ccopts`' + perl_cflags='`$(PERL) -MExtUtils::Embed -e ccopts`' else fail="$fail perl.h" targetname= fi old_LIBS="$LIBS" - LIBS="$old_LIBS `perl -MExtUtils::Embed -e ldopts`" + LIBS="$old_LIBS `$PERL -MExtUtils::Embed -e ldopts`" AC_TRY_LINK([extern char boot_DynaLoader();], [ boot_DynaLoader()], BROKEN=, BROKEN="yes") if test "x$BROKEN" = "x"; then - perl_ldflags='`perl -MExtUtils::Embed -e ldopts`' + perl_ldflags='`$(PERL) -MExtUtils::Embed -e ldopts`' else fail="$fail libperl.so" targetname= fi CFLAGS=$old_CFLAGS + + if test "x$fail" = "x" ; then + if perl -MExtUtils::Embed -e ccopts | grep DEBIAN > /dev/null ; then + AC_MSG_CHECKING([for Debian GNU/Linux libperl.so workaround]) + if test "x$rlm_perl_debian_libperl" = "xyes" ; then + # autodetect libperl and remove minor version + eval `$PERL -V:libperl` + rlm_perl_debian_libperl=${libperl%.[[0-9]]*} + fi + case $rlm_perl_debian_libperl in + # accept anything looking like a shared library + *libperl.so*) + AC_DEFINE_UNQUOTED(DEBIAN_DLOPEN_LIBPERL, "$rlm_perl_debian_libperl") + rlm_perl_debian_libperl="will dlopen($rlm_perl_debian_libperl, RTLD_GLOBAL)" + ;; + *) + rlm_perl_debian_libperl=no + ;; + esac + AC_MSG_RESULT([$rlm_perl_debian_libperl]) + fi + fi + fi targetname=modname Index: src/modules/rlm_perl/rlm_perl.c =================================================================== RCS file: /source/radiusd/src/modules/rlm_perl/rlm_perl.c,v retrieving revision 1.52 diff -u -r1.52 rlm_perl.c --- src/modules/rlm_perl/rlm_perl.c 14 May 2007 22:27:20 -0000 1.52 +++ src/modules/rlm_perl/rlm_perl.c 8 Jul 2007 06:27:26 -0000 @@ -26,6 +26,7 @@ #include <freeradius-devel/radiusd.h> #include <freeradius-devel/modules.h> +#include "config.h" #ifdef DEBUG #undef DEBUG @@ -109,6 +110,9 @@ #ifdef USE_ITHREADS PERL_POOL *perl_pool; #endif +#ifdef DEBIAN_DLOPEN_LIBPERL + void *libperlhandle; +#endif } PERL_INST; /* * A mapping of configuration file names to internal variables. @@ -735,6 +739,17 @@ return -1; } +#ifdef DEBIAN_DLOPEN_LIBPERL + /* make libperl symbols visible to dynamic perl extensions like Data::Dumper + * on Debian GNU/Linux */ + inst->libperlhandle = dlopen(DEBIAN_DLOPEN_LIBPERL, RTLD_LAZY|RTLD_GLOBAL); + if (inst->libperlhandle) { + radlog(L_DBG, "dlopen(%s) returned %p", DEBIAN_DLOPEN_LIBPERL, inst->libperlhandle); + } else { + radlog(L_ERR, "dlopen(%s): %s", DEBIAN_DLOPEN_LIBPERL, dlerror()); + return -1; + } +#endif embed[0] = NULL; if (inst->perl_flags) { @@ -1295,6 +1310,11 @@ perl_free(inst->perl); #endif +#ifdef DEBIAN_DLOPEN_LIBPERL + if (inst->libperlhandle) + dlclose(inst->libperlhandle); +#endif + free(inst); return exitstatus; }