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

I'm trying to replicate the example of a simple XS module given at https://www.lemoda.net/xs/xs-intro/geometry.html

I have this send_string.cpp file

#include "send_string.h" #include "stdio.h" void send_string (const wchar_t * str) { printf ("string\n"); }
And the header send_string.h file is
void send_string (const wchar_t * str);
The package name is Kbh, and the Kbh.xs file is
#include "EXTERN.h" #include "perl.h" #include "XSUB.h" #include "ppport.h" #include "send_string.h" MODULE = Kbh PACKAGE = Kbh PROTOTYPES: DISABLE void send_string(s) const wchar_t * s TYPEMAP: <<HERE const wchar_t * T_PV HERE
My Makefile.pl is
use ExtUtils::MakeMaker; WriteMakefile ( NAME => 'Kbh', VERSION_FROM => 'lib/Kbh.pm', OBJECT => 'Kbh.o send_string.o', )
My lib/Kbh.pm file is
package Kbh; our $VERSION = '0.01'; require XSLoader; XSLoader::load('Kbh', $VERSION); 1;
When I run dmake I get the linking error "Kbh.o:Kbh.c:(.text+0x75): undefined reference to `send_string'"

Thanks for any help

François

Replies are listed 'Best First'.
Re: XS linking problem
by roboticus (Chancellor) on Sep 20, 2017 at 16:42 UTC

    frazap:

    I just entered your example, and after a little fiddling, I was able to reproduce your error:

    $ make . . . stuff elided . . . Kbh.o: In function `XS_Kbh_send_string': /Work/Perl/Perlmonks/XS_linking/Kbh.c:173: undefined reference to `sen +d_string' /Work/Perl/Perlmonks/XS_linking/Kbh.c:173:(.text+0xb3): relocation tru +ncated to fit: R_X86_64_PC32 against undefined symbol `send_string' collect2: error: ld returned 1 exit status make: *** [Makefile:472: blib/arch/auto/Kbh/Kbh.dll] Error 1

    I took a look at the object files it created and saw the following:

    $ objdump.exe -t Kbh.o Kbh.o: file format pe-x86-64 SYMBOL TABLE: [ 0](sec -2)(fl 0x00)(ty 0)(scl 103) (nx 1) 0x0000000000000000 Kbh. +c File [ 2](sec 1)(fl 0x00)(ty 20)(scl 3) (nx 1) 0x0000000000000000 XS_K +bh_send_string AUX tagndx 0 ttlsiz 0x0 lnnos 0 next 0 . . . elided . . . [ 37](sec 0)(fl 0x00)(ty 0)(scl 2) (nx 0) 0x0000000000000000 __im +p_PL_thr_key [ 38](sec 0)(fl 0x00)(ty 20)(scl 2) (nx 0) 0x0000000000000000 pthr +ead_getspecific [ 39](sec 0)(fl 0x00)(ty 20)(scl 2) (nx 0) 0x0000000000000000 Perl +_sv_2pv_flags [ 40](sec 0)(fl 0x00)(ty 20)(scl 2) (nx 0) 0x0000000000000000 send +_string [ 41](sec 0)(fl 0x00)(ty 20)(scl 2) (nx 0) 0x0000000000000000 Perl +_croak_xs_usage [ 42](sec 0)(fl 0x00)(ty 20)(scl 2) (nx 0) 0x0000000000000000 Perl +_xs_handshake [ 43](sec 0)(fl 0x00)(ty 20)(scl 2) (nx 0) 0x0000000000000000 Perl +_newXS_deffile [ 44](sec 0)(fl 0x00)(ty 20)(scl 2) (nx 0) 0x0000000000000000 Perl +_xs_boot_epilog $ objdump.exe -t send_string.o send_string.o: file format pe-x86-64 SYMBOL TABLE: [ 0](sec -2)(fl 0x00)(ty 0)(scl 103) (nx 1) 0x0000000000000000 send +_string.cpp File [ 2](sec 1)(fl 0x00)(ty 20)(scl 2) (nx 1) 0x0000000000000000 _Z11 +send_stringPKc AUX tagndx 0 ttlsiz 0x0 lnnos 0 next 0 . . . elided . . .

    As you can see, Kbh.o expects a symbol named "send_string", but send_string.o provides "_Z11send_stringPKc". The reason is that you put a .cpp suffix on your send_string source file, so gcc compiled it as a C++ program instead of C. C++ allows functions with the same name based on the argument types, and to do so and let the linker still work it does something called "name mangling" to add type information to the symbol name. So either alter the compiler flags to force gcc to compile it as a C program, or do what I did and simply rename send_string.cpp to send_string.c and give it a try. When I did so, it compiled and linked successfully:

    $ make cp lib/Kbh.pm blib/lib/Kbh.pm cp Makefile.pl blib/lib/Makefile.pl Running Mkbootstrap for Kbh () chmod 644 "Kbh.bs" "/usr/bin/perl.exe" "/usr/lib/perl5/5.22/ExtUtils/xsubpp" -typemap "/ +usr/lib/perl5/5.22/ExtUtils/typemap" Kbh.xs > Kbh.xsc && mv Kbh.xsc +Kbh.c gcc -c -DPERL_USE_SAFE_PUTENV -D_GNU_SOURCE -U__STRICT_ANSI__ -ggdb +-O2 -pipe -Wimplicit-function-declaration -fdebug-prefix-map=/mnt/sha +re/maint/perl.x86_64/build=/usr/src/debug/perl-5.22.4-1 -fdebug-prefi +x-map=/mnt/share/maint/perl.x86_64/src/perl-5.22.4=/usr/src/debug/per +l-5.22.4-1 -fwrapv -fno-strict-aliasing -fstack-protector-strong -D_F +ORTIFY_SOURCE=2 -DUSEIMPORTLIB -O3 -DVERSION=\"0.01\" -DXS_VERSION= +\"0.01\" "-I/usr/lib/perl5/5.22/x86_64-cygwin-threads/CORE" Kbh.c gcc -c -DPERL_USE_SAFE_PUTENV -D_GNU_SOURCE -U__STRICT_ANSI__ -ggdb +-O2 -pipe -Wimplicit-function-declaration -fdebug-prefix-map=/mnt/sha +re/maint/perl.x86_64/build=/usr/src/debug/perl-5.22.4-1 -fdebug-prefi +x-map=/mnt/share/maint/perl.x86_64/src/perl-5.22.4=/usr/src/debug/per +l-5.22.4-1 -fwrapv -fno-strict-aliasing -fstack-protector-strong -D_F +ORTIFY_SOURCE=2 -DUSEIMPORTLIB -O3 -DVERSION=\"0.01\" -DXS_VERSION= +\"0.01\" "-I/usr/lib/perl5/5.22/x86_64-cygwin-threads/CORE" send_s +tring.c rm -f blib/arch/auto/Kbh/Kbh.dll g++ --shared -Wl,--enable-auto-import -Wl,--export-all-symbols -Wl,- +-enable-auto-image-base -fstack-protector-strong Kbh.o send_string.o + -o blib/arch/auto/Kbh/Kbh.dll \ /usr/lib/perl5/5.22/x86_64-cygwin-threads/CORE/cygperl5_22.dll + \ chmod 755 blib/arch/auto/Kbh/Kbh.dll "/usr/bin/perl.exe" -MExtUtils::Command::MM -e 'cp_nonempty' -- Kbh.bs + blib/arch/auto/Kbh/Kbh.bs 644

    ...roboticus

    When your only tool is a hammer, all problems look like your thumb.

      Thanks a lot for the use objdump on the object file and for the explanation !

      I saw that there is a ExtUtils::XSpp module but it use build.pl instead of make and I have no experience with this.

      I will translate my cpp code in c

      François

        No need to stoop that low! Instead prefix the functions you want to have C linkage with extern "C":

        extern "C" void send_string (const wchar_t * str);

        If you are forward declaring the function in a header you don't need to provide the extern declaration in the definition. Now you can provide a C API and still have the power of C++ to go forth and conquer the world.

        Premature optimization is the root of all job security