tags:

views:

855

answers:

2

I'm trying to call into a C++ library from Perl on an AIX 5.1 machine. I've created a very simple test project to try to exercise this.

My C++ shared library (test.cpp):

#include <stdio.h>
#include <iostream>

void myfunc()
{
    printf("in myfunc()\n");
    std::cout << "in myfunc() also" << std::endl;
}

My SWIG interface file (test.i):

%module test
%{
void myfunc();
%}
void myfunc();

I then build the shared object like so:

swig -c++ -perl test.i
g++ -c test_wrap.cxx -I/usr/opt/perl5/lib/5.6.0/aix/CORE -o test_wrap.o
g++ -c test.cpp -o test.o
ld -G -bI:/usr/opt/perl5/lib/5.6.0/aix/CORE/perl.exp -bnoentry -bexpall -lc_r test.o test_wrap.o -o test.so

At this point, I have a test.so shared object that should be loadable in perl (via the SWIG generated test.pm). I have a very simple perl script to try to load the shared object and call the one function that I am exporting (test.pl):

#!/usr/bin/perl
use test;
test::myfunc();

When I run test.pl, I get the following output:

in myfunc()
Illegal instruction (core dumped)

If I comment-out the std::cout usage in myfunc, it works without problem. It appears as though using anything in the C++ STL causes a core dump (I tried just declaring a std::vector and std::stringstream, both result in the core dump). I can create a standalone C++ executable that uses the STL without any issues, it's only when called in my shared object when loaded from perl that I get into trouble.

I've also tried using xlc rather than gcc, but I get the same result. I'm thinking there is some funky linker flag that I need to pass in to ensure that all of the linkage occurs correctly? Any ideas are welcome...

Edit: If I link using gcc/xlc instead of invoking the linker directly (ld), I immediately get a segmentation fault. It looks like it crashes when perl is trying to simply load the shared library. Calling ld as I have above is the closest that I've got it to working, but I think I may be missing some libraries or special AIX linker flags for the C++ libraries.

Edit2: Ok, I've got it working. AIX is very fragile when it comes to linking. I ultimately came up with the following link command that seems to be working correctly:

ld -G -bI:/usr/opt/perl5/lib/5.6.0/aix/CORE/perl.exp -bnoentry -bexpall -lC -lc -ldl test.o test_wrap.o -o test.so

The libraries that I linked against are the most relevant. It turns out that the order in which the libraries are mentioned is very important also (ugh). Also note that this is being built against Perl 5.6.0 that ships with AIX 5.1. I've tried building this same simple application against Perl 5.8.8 and it doesn't work. However, I'm pretty sure the much more sane method of linking (using straight gcc/xlc instead of having to call ld directly) seems to work better. So this issue appears to be a bug in the Perl distribution or the linker or something.

Hopefully this will help some poor soul cursed with having to work with AIX...

+4  A: 

Wouldn't you just add your libstdc++ to your ld command? e.g., "-lstdc++"?

What I did on linux, after replicating your problem was:

gcc -g -lstdc++ -shared test*.o -o test.so

Then the problem went away.

(Trying to get the exact right list of libraries for ld was too much work, so I just told gcc to do it for me.)

Tanktalus
A: 

I know nothing about SWIG, but you might also want to check that it's expecting a function using cdecl (rather than pascal, fastcall, or some other calling convention). Using the wrong one between tools can lead to "bad things happening" (usually stack corruption, as far as I can tell).

Head Geek