[reply cross-posted to Module::Build list; reply-to header set to perl-xs@perl.org
]
On Sep 3, 2008, at 6:23 AM, Sisyphus wrote:
Basically, if you have a perl dll (by which I mean, eg, the
Digest::SHA dll) and you want to directly access a function from
within that dll using XS or Inline::C, how do you do that ?
The brute-force way is cram function addresses through Perl variables,
as suggested at <http://www.perlmonks.org/?node_id=691174> and
described in the Time::HiRes POD documentation at <http://perldoc.perl.org/Time/HiRes.html#C-API
>. The latest version of Lingua::Stem::Snowball (0.952) takes this
route so that svn trunk for KinoSearch can access those addresses.
(The API isn't public yet, but I can get away with private API access
because I maintain both distros.) The XS BOOT: section which does the
exporting for L::S::Snowball is pasted below my sig.
The advantage of this technique is that it's highly portable. The
big disadvantage is that it doesn't scale. You also have to worry
about C symbol conflicts and you have to use function pointers rather
than real C functions.
With most Windows dll's, you can just use LoadLibrary() to get a
handle to the dll, and then use GetProcAddress() to return the
address of the function you want to access.
For the first part, there's no problem - one can easily use
LoadLibrary() to return a handle to SHA.dll. It's the second part
that presents the problem. GetProcAddress() can only return the
address of functions/variables that are *exported* ... and most of
the functions in SHA.dll (eg 'hashsize') are *not* exported.
When the Windows DLL is linked, it has to be told what symbols should
be exportable. The process is analogous to exporting functions from
Perl modules using Exporter:
package Foo;
use base qw( Exporter );
BEGIN { our @EXPORT_OK = qw( do_stuff ); }
The problem is that the way you tell the linker to export symbols is
platform-specific. For MSVC, the interface is described at <http://msdn.microsoft.com/en-us/library/z4zxe9k8(VS.80).aspx
>:
You can export functions from a DLL using two methods:
* Create a module definition (.def) file and use the .def
file when building the DLL. Use this approach if you want
to export functions from your DLL by ordinal rather than
by name.
* Use the keyword __declspec(dllexport) in the function's
definition.
The .def file is a text file that's analogous to the @EXPORT_OK
array. The format is described at <http://msdn.microsoft.com/en-us/library/d91k01sh(VS.80).aspx
>.
What might be nice is to be able to feed a list of C function names to
ExtUtils::CBuilder or Module::Build (which would pass to CBuilder),
and have CBuilder generate the .def file. We'd then have covered
symbol exporting both unixen (easy if cryptic: use Dynaloader rather
than XSLoader and put C<sub dl_load_flags {0x01}> in your Perl module
code) and MSVC. That would cover most Perl installations out there.
Marvin Humphrey
Rectangular Research
http://www.rectangular.com/
=============================================================
In Snowball.xs:
BOOT:
{
SV *sb_stemmer_list_sv = newSViv(PTR2IV(sb_stemmer_list));
SV *sb_stemmer_new_sv = newSViv(PTR2IV(sb_stemmer_new));
SV *sb_stemmer_delete_sv = newSViv(PTR2IV(sb_stemmer_delete));
SV *sb_stemmer_stem_sv = newSViv(PTR2IV(sb_stemmer_stem));
SV *sb_stemmer_length_sv = newSViv(PTR2IV(sb_stemmer_length));
hv_store(PL_modglobal, "Lingua::Stem::Snowball::sb_stemmer_list",
39,
sb_stemmer_list_sv, 0);
hv_store(PL_modglobal, "Lingua::Stem::Snowball::sb_stemmer_new",
38,
sb_stemmer_new_sv, 0);
hv_store(PL_modglobal,
"Lingua::Stem::Snowball::sb_stemmer_delete", 41,
sb_stemmer_delete_sv, 0);
hv_store(PL_modglobal, "Lingua::Stem::Snowball::sb_stemmer_stem",
39,
sb_stemmer_stem_sv, 0);
hv_store(PL_modglobal,
"Lingua::Stem::Snowball::sb_stemmer_length", 41,
sb_stemmer_length_sv, 0);
}