Ticket #522: xapian-dlopen-fix-with-test-case.patch

File xapian-dlopen-fix-with-test-case.patch, 8.6 KB (added by David F. Skoll, 13 years ago)

Test case illustrating dlopen problem.

  • Xapian.pm

    diff --git a/Xapian.pm b/Xapian.pm
    index 643edc1..d071721 100644
    a b require DynaLoader;  
    3838
    3939our @ISA = qw(DynaLoader);
    4040
     41# We need to use the RTLD_GLOBAL flag to dlopen() so that other C++
     42# modules that link against libxapian.so get the *same* value for all the
     43# weak symbols (eg, the exception classes)
     44sub dl_load_flags { 0x01 }
     45
    4146# This allows declaration       use Search::Xapian ':all';
    4247# If you do not need this, moving things directly into @EXPORT or @EXPORT_OK
    4348# will save memory.
  • new file t/ticket-522/Makefile.PL

    diff --git a/t/ticket-522/.gitignore b/t/ticket-522/.gitignore
    new file mode 100644
    index 0000000..eb85e30
    - +  
     1use ExtUtils::MakeMaker;
     2use strict;
     3use Config;
     4
     5# Suppress warnings about parameters we allow the user to specify.
     6$ExtUtils::MakeMaker::Recognized_Att_Keys{CXX} = 1;
     7$ExtUtils::MakeMaker::Recognized_Att_Keys{XAPIAN_CONFIG} = 1;
     8
     9my $builddir;
     10
     11my $srcdir = $0;
     12if ($srcdir =~ s!/([^/]*)$!!) {
     13    # Set $0 to be just the leafname.  If we don't, WriteMakefile() reruns this
     14    # script for reasons unknown, leading to a seemingly infinite loop
     15    # consuming increasing amounts of memory.  With setting $0, it still reruns
     16    # this script, but only once.
     17    $0 = $1;
     18    chomp($builddir = `pwd`);
     19    chdir $srcdir;
     20}
     21
     22my $xapian_config;
     23my $CC;
     24for (@ARGV) {
     25    if (/^XAPIAN_CONFIG=(.*)/) {
     26        $xapian_config = $1;
     27    } elsif (/^CXX=(.*)/) {
     28        $CC = $1;
     29    }
     30}
     31
     32if (!defined $xapian_config && exists $ENV{XAPIAN_CONFIG}) {
     33    $xapian_config = $ENV{XAPIAN_CONFIG};
     34    push @ARGV, "XAPIAN_CONFIG=$xapian_config";
     35}
     36$xapian_config ||= 'xapian-config';
     37
     38if (!defined $CC && exists $ENV{CXX}) {
     39    $CC = $ENV{CXX};
     40    push @ARGV, "CXX=$CC";
     41}
     42$CC ||= 'g++';
     43
     44my $LD = '$(CC)';
     45if ($^O eq 'cygwin' and $CC eq 'g++') {
     46    # Cygwin packages of Perl < 5.9.5 used "ld2" for $Config{ld} and
     47    # $Config{lddlflags} didn't contain -shared so we need to specify
     48    # this explicitly.  Perl >= 5.9.5 package do away with "ld2", but
     49    # it should be harmless to specify "-shared" there.
     50    $LD = 'g++ -shared';
     51}
     52
     53my $xver = `$xapian_config --version`;
     54if ($xver eq '') {
     55    print STDERR <<END;
     56$xapian_config not found.
     57
     58You need Xapian installed before you can build CanIt::LogSearch::XapianXSIndexer.  If you have
     59installed Xapian from a package, you will also need to install the correspoding
     60-dev or -devel package.  If Xapian is installed but xapian-config isn't on your
     61PATH you can tell Makefile.PL this by running it like so:
     62
     63    perl Makefile.PL XAPIAN_CONFIG=/path/to/xapian-config
     64END
     65    # Perversely, the CPAN automatic testing script expects exit status 0 to
     66    # indicate "can't build because of missing dependencies" (which it
     67    # distinguishes from "all OK" by seeing if Makefile is generated).  So we
     68    # exit with status 0 in this case to avoid being spammed with useless
     69    # "bug" reports from testers without Xapian installed.
     70    exit(0);
     71}
     72chomp($xver);
     73$xver =~ s/.*\s//; # "xapian 1.2.0" -> "1.2.0"
     74
     75my $inc = `$xapian_config --cxxflags`;
     76chomp($inc);
     77
     78my @writemakefile_args = ();
     79my $libsvar = 'LIBS';
     80my $libs = `$xapian_config --libs 2> /dev/null`;
     81chomp($libs);
     82my ($xapian_config_dir) = $xapian_config =~ /^(.*?)[^\/]*$/;
     83if ($? || ($xapian_config_dir ne '' && -f "${xapian_config_dir}Makefile")) {
     84    # Assume we're being asked to build against an uninstalled xapian-core.
     85    my $libtool = "${xapian_config_dir}libtool";
     86    unless (-x $libtool) {
     87        die "You've asked me to link against what appears to be an uninstalled xapian-core tree, but I can't find libtool in that tree\n";
     88    }
     89
     90    # We can't pass a .la file in LIBS since MakeMaker "knows better" and
     91    # ignores it.  Passing it in LDLOADLIBS works, but generates a warning.
     92    # We can avoid the warning by setting LDLOADLIBS using 'macro'.
     93    $libsvar = 'macro';
     94    $libs = `$xapian_config --ltlibs`;
     95    chomp($libs);
     96    $libs = {'LDLOADLIBS' => $libs};
     97    $LD = "$libtool --tag=CXX --mode=link $CC -avoid-version -module";
     98    $LD .= " -rpath \$(PERL_ARCHLIB)/auto/\$(FULLEXT)";
     99    $LD .= " -shrext .".$Config{'dlext'};
     100    $CC = "$libtool --tag=CXX --mode=compile $CC";
     101    push @writemakefile_args, (
     102        'OBJ_EXT'       => '.lo',
     103        'DLEXT'         => 'la',
     104        'FULLPERL'      => '$(PERL) "-I$(INST_ARCHAUTODIR)/.libs"',
     105    );
     106}
     107
     108# Filter out some gcc options which g++ doesn't support.
     109my $CCFLAGS = $Config{'ccflags'};
     110# Perl is built with -Wdeclaration-after-statement on RHEL5 - this isn't
     111# meaningful for C++ - it only emits a warning but it's easy to fix.
     112$CCFLAGS =~ s/(?:^|\s+)-Wdeclaration-after-statement(?:\s+|$)/ /;
     113# The generated code causes "variable may be used uninitialized" warnings
     114# if Perl was built with -Wall.
     115$CCFLAGS =~ s/(^|\s+)-Wall(\s+|$)/$1-Wall -Wno-uninitialized$2/;
     116
     117# See lib/ExtUtils/MakeMaker.pm for details of how to influence
     118# the contents of the Makefile that is written.
     119push @writemakefile_args, (
     120    'NAME'              => 'SymbolTest',
     121    'VERSION_FROM'      => 'SymbolTest.pm', # finds $VERSION
     122    'PREREQ_PM'         => {}, # e.g., Module::Name => 1.1
     123    AUTHOR        => q{Dave O'Neill <dmo@roaringpenguin.com>},
     124    $libsvar            => $libs, # e.g., '-lm'
     125    'DEFINE'            => '', # e.g., '-DHAVE_SOMETHING'
     126    'CC'                => $CC,
     127    'CCFLAGS'           => $CCFLAGS,
     128    'LD'                => $LD,
     129    'INC'               => $inc, # e.g., '-I/usr/include/other'
     130    'OBJECT'            => '$(BASEEXT)$(OBJ_EXT)',
     131    'XSOPT'             => '-C++ -hiertype',
     132);
     133WriteMakefile(@writemakefile_args);
  • new file t/ticket-522/SymbolTest.pm

    diff --git a/t/ticket-522/SymbolTest.pm b/t/ticket-522/SymbolTest.pm
    new file mode 100644
    index 0000000..e68161c
    - +  
     1package SymbolTest;
     2use strict;
     3use warnings;
     4use vars qw( $VERSION @ISA );
     5
     6$VERSION = '1.2.3.0';
     7
     8require DynaLoader;
     9@ISA = qw( DynaLoader );
     10
     11# We need to use the RTLD_GLOBAL flag to dlopen() so that other C++
     12# modules that link against libxapian.so get the *same* value for all the
     13# weak symbols (eg, the exception classes)
     14#### sub dl_load_flags { 0x01 }
     15
     16bootstrap SymbolTest $VERSION;
  • new file t/ticket-522/SymbolTest.xs

    diff --git a/t/ticket-522/SymbolTest.xs b/t/ticket-522/SymbolTest.xs
    new file mode 100644
    index 0000000..4448d04
    - +  
     1#include <xapian.h>
     2
     3extern "C" {
     4#include "EXTERN.h"
     5#include "perl.h"
     6#include "XSUB.h"
     7}
     8
     9using namespace Xapian;
     10
     11class SymbolTest {
     12public:
     13        SymbolTest () {};
     14
     15        ~SymbolTest() {};
     16};
     17
     18MODULE = SymbolTest     PACKAGE = SymbolTest
     19
     20PROTOTYPES: ENABLE
     21
     22SymbolTest *
     23SymbolTest::new()
     24
     25void
     26SymbolTest::DESTROY()
     27
     28void
     29SymbolTest::throw_from_libxapian()
     30   CODE:
     31        WritableDatabase *db;
     32
     33        try {
     34                db = new WritableDatabase("/dev/null", DB_CREATE_OR_OPEN);
     35        } catch (const Error & error) {
     36                croak("Exception of type %s caught and rethrown by SymbolTest", error.get_type() );
     37        } catch (...) {
     38                croak("Unknown C++ exception caught in SymbolTest");
     39        }
     40
  • new file t/ticket-522/t/no-symbol-problems.t

    diff --git a/t/ticket-522/t/no-symbol-problems.t b/t/ticket-522/t/no-symbol-problems.t
    new file mode 100644
    index 0000000..8ce9fcd
    - +  
     1use Test::More tests => 2;
     2use FindBin;
     3
     4use lib ("$FindBin::Bin/../blib/arch", "$FindBin::Bin/../blib/lib");
     5use lib ("$FindBin::Bin/../../../blib/arch", "$FindBin::Bin/../../../blib/lib");
     6
     7use_ok("SymbolTest");
     8eval { SymbolTest->new->throw_from_libxapian() };
     9like( $@, qr/Exception of type DatabaseOpeningError caught and rethrown by SymbolTest/, 'Exception properly caught');
  • new file t/ticket-522/t/symbol-problems.t

    diff --git a/t/ticket-522/t/symbol-problems.t b/t/ticket-522/t/symbol-problems.t
    new file mode 100644
    index 0000000..20a4ac7
    - +  
     1use Test::More tests => 2;
     2use FindBin;
     3
     4
     5use lib ("$FindBin::Bin/../blib/arch", "$FindBin::Bin/../blib/lib");
     6use lib ("$FindBin::Bin/../../../blib/arch", "$FindBin::Bin/../../../blib/lib");
     7
     8use Search::Xapian qw( :all );
     9
     10use_ok("SymbolTest");
     11eval { SymbolTest->new->throw_from_libxapian() };
     12like( $@, qr/Exception of type DatabaseOpeningError caught and rethrown by SymbolTest/, 'Exception properly caught');
  • new file t/ticket-522/typemap

    diff --git a/t/ticket-522/typemap b/t/ticket-522/typemap
    new file mode 100644
    index 0000000..4d80d68
    - +  
     1TYPEMAP
     2SymbolTest *    O_OBJECT
     3
     4OUTPUT
     5O_OBJECT
     6        sv_setref_pv( $arg, CLASS, (void*)$var );
     7
     8INPUT
     9O_OBJECT
     10        if( sv_isobject($arg) && (SvTYPE(SvRV($arg)) == SVt_PVMG) )
     11                $var = ($type)SvIV((SV*)SvRV( $arg ));
     12        else{
     13                warn( \"${Package}::$func_name() -- $var is not a blessed SV reference\" );
     14                XSRETURN_UNDEF;
     15        }