FloydATC has asked for the wisdom of the Perl Monks concerning the following question:

I want to write a shared C library to be used from Perl. In a desperate attempt to figure h2xs out, I have written the following:
// libtwintree.h: int return_one( void ); int return_zero( void );
// libtwintree.c: #include "libtwintree.h" int return_one( void ) { return 1; } int return_zero( void ) { return 0; }
Obviously these are just placeholders for the real functions that this library will implement, it's just that before I write tons of code I really need to get the h2xs monster to cooperate. Anyway, here's the Makefile I'm using to try and fit the pieces together:
TwinTree.pm : TwinTree.xs cd TwinTree && \ perl Makefile.PL && \ make && \ make test && \ make install TwinTree.xs : libtwintree.so install mkdir -p TwinTree && \ cp libtwintree.h TwinTree && \ h2xs -Oxan TwinTree -L/usr/local/lib -llibtwintree libtwintree +.h libtwintree.so : libtwintree.o gcc -shared -Wl,-soname,libtwintree.so -o libtwintree.so libtw +intree.o -lc libtwintree.o : gcc -fPIC -g -c -Wall libtwintree.c clean : rm -Rf *.o *.so TwinTree install : libtwintree.so cp libtwintree.so /usr/local/lib && \ ldconfig -n /usr/local/lib
According to the h2xs manpage, the -x switch is supposed to "Automatically generate XSUBs basing on function declarations in the header file". So... why is it that the generated TwinTree.xs looks like this?
#include "EXTERN.h" #include "perl.h" #include "XSUB.h" #include "ppport.h" #include "const-c.inc" MODULE = TwinTree PACKAGE = TwinTree INCLUDE: const-xs.inc
No XSUBs, the entire module is basically 500K of absolutely nothing. What am I missing that's so obvious nobody seems to think it's worth mentioning in the manpage?

Not that I think it matters, but I'm running perl 5.8.8 and uname -a is Linux atlas.atc.no 2.6.27-briullov.1 #1 SMP Fri Apr 3 19:34:58 MSD 2009 i686 i686 i386 GNU/Linux.

Edit: pasted the proper contents of twintree.c

-- Time flies when you don't know what you're doing

Replies are listed 'Best First'.
Re: Why does the h2xs -x switch not generate XSUBs?
by syphilis (Archbishop) on Jul 24, 2009 at 11:51 UTC
    Can't really help out with h2xs, and I'm not entirely sure that I understand what you're doing. You say you want "to write a shared C library to be used from Perl", but then you seem to merely want to generate an XS file with a couple of functions in it. Anyway, fwiw, which may not be much:
    <plug>
    I can generate an XS file, a Makefile.PL and a stub TwinTree.pm using InlineX-C2XS and libtwintree.c.
    One caveat - because it's using Inline::C, and because Inline::C doesn't understand 'void' as the argument list, I've had to rewrite libtwintree.c as:
    // libtwintree.c: #include "libtwintree.h" int return_one() { return 1; } int return_zero() { return 0; }
    That 'void' in the argument list would be, I think, incorrect if included in the XS functions. (It's certainly not needed, anyway.)

    Then it's just a matter of running
    perl -MInlineX::C2XS="c2xs" -we 'c2xs("TwinTree","TwinTree",{SRC_LOCATION=>"./libtwintree.c",WRITE_MAKEFILE_PL=>1,VERSION=>0.01,WRITE_PM=>1})'
    and you'll find TwinTree.xs, Makefile.PL and TwinTree.pm all sitting in the cwd:
    TwinTree.xs:
    #include "EXTERN.h" #include "perl.h" #include "XSUB.h" // libtwintree.c: #include "libtwintree.h" int return_one() { return 1; } int return_zero() { return 0; } MODULE = TwinTree PACKAGE = TwinTree PROTOTYPES: DISABLE int return_one () int return_zero ()
    TwinTree.pm:
    package TwinTree; use strict; require Exporter; *import = \&Exporter::import; require DynaLoader; $TwinTree::VERSION = '0.01'; DynaLoader::bootstrap TwinTree $TwinTree::VERSION; @TwinTree::EXPORT = (); @TwinTree::EXPORT_OK = (); sub dl_load_flags {0} # Prevent DynaLoader from complaining and croaki +ng 1;
    Makefile.PL:
    use ExtUtils::MakeMaker; my %options = %{ { 'TYPEMAPS' => [], 'NAME' => 'TwinTree', 'INC' => '', 'VERSION' => '0.01' } }; WriteMakefile(%options); # Remove the Makefile dependency. Causes problems on a few systems. sub MY::makefile { '' }
    That's using version 0.14, which has only just been uploaded to CPAN, amd may take a while to reach all mirrors. Version 0.13 is quite functional, but adds the cwd to INC and the standard perl typemaps to TYPEMAP in the Makefile.PL - which neither breaks nor achieves anything (but is a bit annoying).
    </plug>

    Cheers,
    Rob
Re: Why does the h2xs -x switch not generate XSUBs?
by Anonymous Monk on Jul 24, 2009 at 09:58 UTC
    If I follow
    SYNOPSIS h2xs [OPTIONS ...] [headerfile ... [extra_libraries]]
    and change order to
    h2xs -Oxan TwinTree libtwintree.h -L/usr/local/lib -llibtwintree
    I get
    Scanning libtwintree.h for functions... 'cppstdin' is not recognized as an internal or external command, operable program or batch file. 'cppstdin' is not recognized as an internal or external command, operable program or batch file.
    Your hand makefile scares me :) I thought Makefile.PL make makefile.
      See, normally the order doesn't matter but in this case it obviously does. So noted. So I change the order, this time TwinTree.xs shows some improvement although I still can't see any actual XSUB code:
      #include "EXTERN.h" #include "perl.h" #include "XSUB.h" #include "ppport.h" #include <libtwintree.h> #include "const-c.inc" MODULE = TwinTree PACKAGE = TwinTree INCLUDE: const-xs.inc int return_one() int return_zero()
      Declarations are a good place to start, but the definitions are still missing. When trying 'make test' on the module, this is what I get:
      PERL_DL_NONLAZY=1 /usr/bin/perl "-MExtUtils::Command::MM" "-e" "test_h +arness(0, 'blib/lib', 'bl +ib/arch')" t/*.t t/TwinTree....NOK 1 # Failed test 'use TwinTree;' # at t/TwinTree.t line 9. # Tried to use 'TwinTree'. # Error: Can't load '/home/floyd/twintree/TwinTree/blib/arch/auto +/TwinTree/ TwinTree.so' fo +r module TwinTree: /home/floyd/twintree/TwinTree/blib/arch/auto/T + winTree/TwinTree.so: undefine +d symbol: return_one at /usr/lib/perl5/5.8.8/i386-l + inux-thread-multi/DynaLoader.pm line 230. # at (eval 4) line 2 # Compilation failed in require at (eval 4) line 2. # BEGIN failed--compilation aborted at (eval 4) line 2. # Looks like you failed 1 test of 1. t/TwinTree....dubious Test returned status 1 (wstat 256, 0x100) DIED. FAILED test 1 Failed 1/1 tests, 0.00% okay Failed Test Stat Wstat Total Fail Failed List of Failed ---------------------------------------------------------------------- +--------- t/TwinTree.t 1 256 1 1 100.00% 1 Failed 1/1 test scripts, 0.00% okay. 1/1 subtests failed, 0.00% okay. make[1]: *** [test_dynamic] Error 1 make[1]: Leaving directory `/home/floyd/twintree/TwinTree' make: *** [TwinTree.pm] Error 2
      By the way, don't be scared by that handmade Makefile, that's for the C project. The h2xs generated Makefile.PL lives in the TwinTree subdirectory.

      -- Time flies when you don't know what you're doing

        although I still can't see any actual XSUB code

        No, what you have there is sufficient.

        ... int return_one() int return_zero()

        What you posted later is overkill.

        ... int return_one() CODE: RETVAL = return_one(); OUTPUT: RETVAL int return_zero() CODE: RETVAL = return_one(); OUTPUT: RETVAL
        Declarations are a good place to start, but the definitions are still missing.

        I'm sorry, what?

        When trying 'make test' on the module, this is what I get

        How did you compile libtwintree? Does it export symbols return_one return_zero? Is libtwintree.so in path? What does ldd /blib/arch/auto/TwinTree/TwinTree.so return?