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

I'm working on a module which is a Perl interface to an existing C++ library at my work. In particular, there's a constant in the C++ header that I want to expose in Perl, rather than duplicating the definition and risking them drift out of sync if someone forgets to update the code in one place or the other. My XS experience to date is limited, but after looking through perlguts, perlapi and some Googling, here's what I've come up with so far:

MyModule.pm:

package MyModule; use vars qw(@ISA $VERSION $CONSTANT_NAME); BEGIN { @ISA = qw(DynaLoader); $VERSION = '0.01'; $CONSTANT_NAME = -1; } bootstrap MyModule $VERSION;

MyModule.xs:

#include "my_constants.h" MODULE = MyModule PACKAGE = MyModule BOOT: { SV* const_sv = get_sv( "MyModule::CONSTANT_NAME", 0 ); SvIV_set( const_sv, CONSTANT_VALUE_FROM_C_LIBRARY ); SvIOK_on( const_sv ); SvREADONLY_on( const_sv ); }

This works in the sense that it compiles and provides the expected value in my simple test one-liner (basically just "use MyModule; print $MyModule::CONSTANT_NAME"). However, I'm not sure whether this is actually the best way to go about it -- in particular, setting $CONSTANT_NAME in the BEGIN block and then changing it again in the XS seems clunky. It's also possible that this is subtly broken in some way that I haven't discerned yet (e.g. threads or something).

My question, then, is (a) whether this as written is incorrect in any specific way, and (b) whether there's a better approach that I ought to be using instead. What say ye, monks?

Replies are listed 'Best First'.
Re: XS: exposing C++ library constant as package variable
by BrowserUk (Patriarch) on Oct 06, 2015 at 22:13 UTC

    If you add GV_ADD in place of the 0 as the second argument to get_sv(), then you shouldn't need to pre-declare or initialise MyModule::CONSTANT_NAME in the Perl code, as it will be created for you.

    As for caveats with regard to threading; as it is a constant, there should be none.


    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority". I knew I was on the right track :)
    In the absence of evidence, opinion is indistinguishable from prejudice.

      As for caveats with regard to threading

      It's a normal Perl scalar. It will get cloned on thread creation like every other. Each thread will be accessing its own copy of it. No problem.

      Update: s/a different/its own/

        Each thread will be accessing a different copy of it

        I would have expected the copies to be identical, and that the SvREADONLY_on would ensure that they stay identical.
        Of course, my expectations are often wrong - especially re threads. (IOW, someone please correct me where necessary.)

        Cheers,
        Rob

      I tried just using GV_ADD, but it gave me a segfault:

      mymodule.xs:113 is where I'm calling SvIV_set. The same thing happens if I leave $CONSTANT_NAME in the use vars statement, but don't initialize it in BEGIN.

        Address 0x18 is not stack'd, malloc'd or (recently) free'd

        That suggests that get_sv() is returning an invalid SV*; which it shouldn't, if the docs are to be believed:

        get_sv Returns the SV of the specified Perl scalar. flags are passed to gv_fe +tchpv. If GV_ADD is set and the Perl variable does not exist then it +will be created. If flags is zero and the variable does not exist the +n NULL is returned. NOTE: the perl_ form of this function is deprecated. SV* get_sv(const char *name, I32 flags)

        I think your only course of action (other than sticking with the way you have that works) is to write a minimal testcase and raise a perlbug.

        P5p will either: correct the code; or correct my interpretation of the docs.

        Of course, any resolution will take time, so you'll probably need to stick with what you originally had for now anyway. Sorry for the bum steer.


        With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority". I knew I was on the right track :)
        In the absence of evidence, opinion is indistinguishable from prejudice.
Re: XS: exposing C++ library constant as package variable
by RonW (Parson) on Oct 07, 2015 at 22:38 UTC

    Have you considered using h2ph to generate Perl constants directly from the .h files?

    Or, since it's a few specific constants, you could write your own Perl script to extract just those constants and generate Perl constants from them. (Might want to look at constant.pm if you do write your own extractor.)

    I think Perl constants have less access overhead and you'd only have to run the extractor when building the XS library module.

      Why make more work when you don't have to?