[XS] .h constants -> Perl subs (like POSIX' "errno_h")?

Discussion in 'Perl Misc' started by Ivan Shmakov, Jul 3, 2013.

  1. Ivan Shmakov

    Ivan Shmakov Guest

    Is there an easy way to make a bunch of C constants (as in:
    #define) available as Perl subroutines (just like, e. g., POSIX
    does for the errno.h constants)?

    I've looked at POSIX.xs, POSIX.pm [1, 2], but don't seem to get
    it. (Somehow, there do not seem to be any references to, say,
    ENOENT, other than that in the export list.)

    Surely, I can follow the example at SQLite.xs [3]:

    static int
    OK()
    CODE:
    RETVAL = SQLITE_OK;
    OUTPUT:
    RETVAL

    But that seems overly repetitive and error-prone. (Given that I
    need to handle some 156 such constants, anyway.)

    TIA.

    [1] http://cpansearch.perl.org/src/RJBS/perl-5.18.0/ext/POSIX/POSIX.xs
    [2] http://cpansearch.perl.org/src/RJBS/perl-5.18.0/ext/POSIX/lib/POSIX.pm
    [3] http://cpansearch.perl.org/src/ISHIGAKI/DBD-SQLite-1.39/SQLite.xs

    --
    FSF associate member #7257
     
    Ivan Shmakov, Jul 3, 2013
    #1
    1. Advertising

  2. Ivan Shmakov <> writes:

    > Is there an easy way to make a bunch of C constants (as in:
    > #define) available as Perl subroutines (just like, e. g., POSIX
    > does for the errno.h constants)?


    In the past I have used the h2ph tools for this. It requires some post
    processing to make it look like a modern perl module with sane exports.

    //Makholm
     
    Peter Makholm, Jul 3, 2013
    #2
    1. Advertising

  3. Ivan Shmakov

    Ivan Shmakov Guest

    Ivan Shmakov, Jul 3, 2013
    #3
  4. Ivan Shmakov <> writes:
    > Is there an easy way to make a bunch of C constants (as in:
    > #define) available as Perl subroutines (just like, e. g., POSIX
    > does for the errno.h constants)?


    In case of a new module, this is part of what h2xs does. I'm also
    using C::Scan::Constants when more 'dynamic'(ically changing) headers
    are involved.
     
    Rainer Weikusat, Jul 3, 2013
    #4
  5. Ivan Shmakov

    Ivan Shmakov Guest

    >>>>> Rainer Weikusat <> writes:
    >>>>> Ivan Shmakov <> writes:


    >> Is there an easy way to make a bunch of C constants (as in: #define)
    >> available as Perl subroutines (just like, e. g., POSIX does for the
    >> errno.h constants)?


    > In case of a new module, this is part of what h2xs does.


    It seems to do more than that: it prepares a complete template
    for a new module. Which is certainly nice and worth looking at,
    but I already have started working on that module, thus it isn't
    all that helpful.

    Besides, the data gathered by h2xs(1) ends up in the respective
    WriteConstants () invocation in Makefile.PL. Which then does
    the thing, as I was able to figure out.

    > I'm also using C::Scan::Constants when more 'dynamic'(ically
    > changing) headers are involved.


    ACK, thanks for the pointer.

    (To note is that the C::Scan::Constants documentation also
    points to WriteConstants ().)

    --
    FSF associate member #7257
     
    Ivan Shmakov, Jul 5, 2013
    #5
  6. Ivan Shmakov <> writes:
    >>>>>> Rainer Weikusat <> writes:
    >>>>>> Ivan Shmakov <> writes:
    > >> Is there an easy way to make a bunch of C constants (as in: #define)
    > >> available as Perl subroutines


    [...]

    > > I'm also using C::Scan::Constants when more 'dynamic'(ically
    > > changing) headers are involved.

    >
    > ACK, thanks for the pointer.
    >
    > (To note is that the C::Scan::Constants documentation also
    > points to WriteConstants ().)


    The more interesting part is that it provides a reasonably working
    (the version I'm using required manual fixups because it can't cope
    with #defines which don't include an expansion, eg, guard macros)
    'easy to use' way to extract 'constant information' from a bunch of C
    header files. Eg, I have a Perl (extension) module capable of parsing
    a (set of) racoon config file(s) based on a shared library containing
    the actual racoon parser code (based on a thorough reorganization of
    the racoon source code) and I'm using a script looking like this:

    ---------------
    use C::Scan::Constants;

    my @hdrs = qw(/usr/local/include/racoon/ipsecdoi_id.h
    /usr/local/include/racoon/ipsec_doi.h
    /usr/local/include/racoon/handler.h
    /usr/local/include/racoon/isakmp.h
    /usr/local/include/racoon/oakley.h
    /usr/local/include/racoon/remoteconf.h);
    my @cs = extract_constants_from(@hdrs);
    write_constants_module('MECS::Racoonconf', @cs);
    ---------------

    to add the IPsec-related constants I need to that (supposed to be
    executed manually whenever 'something changed').
     
    Rainer Weikusat, Jul 5, 2013
    #6
  7. On 7/2/2013 11:05 PM, Ivan Shmakov wrote:
    > Is there an easy way to make a bunch of C constants (as in:
    > #define) available as Perl subroutines (just like, e. g., POSIX
    > does for the errno.h constants)?
    >
    > I've looked at POSIX.xs, POSIX.pm [1, 2], but don't seem to get
    > it. (Somehow, there do not seem to be any references to, say,
    > ENOENT, other than that in the export list.)
    >
    > Surely, I can follow the example at SQLite.xs [3]:
    >
    > static int
    > OK()
    > CODE:
    > RETVAL = SQLITE_OK;
    > OUTPUT:
    > RETVAL
    >
    > But that seems overly repetitive and error-prone. (Given that I
    > need to handle some 156 such constants, anyway.)
    >
    > TIA.
    >
    > [1] http://cpansearch.perl.org/src/RJBS/perl-5.18.0/ext/POSIX/POSIX.xs
    > [2] http://cpansearch.perl.org/src/RJBS/perl-5.18.0/ext/POSIX/lib/POSIX.pm
    > [3] http://cpansearch.perl.org/src/ISHIGAKI/DBD-SQLite-1.39/SQLite.xs
    >


    Could you just transform 'em to perl constants, eg,

    BEGIN {
    my %const = map {chomp; (split)[1,2]; }
    qx{ grep '^#define' /path/to/*.h };
    my $code;
    while ( my($k,$v) = each %const ) {
    $code .= "$k => $v,";
    }
    eval "use constant {$code}";
    die $@ if $@;
    }


    --
    Charles DeRykus
     
    Charles DeRykus, Jul 6, 2013
    #7
  8. Ivan Shmakov

    Ivan Shmakov Guest

    >>>>> Charles DeRykus <> writes:
    >>>>> On 7/2/2013 11:05 PM, Ivan Shmakov wrote:


    >> Is there an easy way to make a bunch of C constants (as in: #define)
    >> available as Perl subroutines (just like, e. g., POSIX does for the
    >> errno.h constants)?


    [...]

    > Could you just transform 'em to perl constants, eg,


    > BEGIN {
    > my %const = map {chomp; (split)[1,2]; }
    > qx{ grep '^#define' /path/to/*.h };


    Surely I could. The question is: how do I keep my code in sync
    with the library's it duplicates?

    [...]

    --
    FSF associate member #7257
     
    Ivan Shmakov, Jul 6, 2013
    #8
  9. Charles DeRykus <> writes:
    > On 7/2/2013 11:05 PM, Ivan Shmakov wrote:
    >> Is there an easy way to make a bunch of C constants (as in:
    >> #define) available as Perl subroutines (just like, e. g., POSIX
    >> does for the errno.h constants)?


    [...]

    > Could you just transform 'em to perl constants, eg,
    >
    > BEGIN {
    > my %const = map {chomp; (split)[1,2]; }
    > qx{ grep '^#define' /path/to/*.h };
    > my $code;
    > while ( my($k,$v) = each %const ) {
    > $code .= "$k => $v,";
    > }
    > eval "use constant {$code}";
    > die $@ if $@;
    > }


    That's broken. Some people indent nested preprocessor directives, eg

    #ifdef BLAH
    # define OOPS "yodel"
    #else
    # define OOPS "---"
    #endif

    Macro expansions may be multiline, eg

    #define OTHERTINGER \
    "dock"\
    "wok"\
    "clock"\
    "cat"\
    "bat"\
    "flat"\
    "spherical"\
    "dot"

    There might not by any expansions and macros can have arguments (this
    is likely not an exhausive list). Also, numerical constants can be
    defined via enum which makes them visible to 'other tools' (like
    debuggers) and prevents 'unexpected substitutions' as in

    #include <stdio.h>

    #define oo ar

    int main(void)
    {
    int oo = 5;
    printf("%d\n", ar);
    return 0;
    }

    You also don't need the eval, constant.pm also works with anonymous
    hashes

    perl -e 'use constant { A => 2, B => 3 }; print A + B, "\n";'
     
    Rainer Weikusat, Jul 6, 2013
    #9
  10. Rainer Weikusat <> writes:
    > Charles DeRykus <> writes:


    [...]

    >> BEGIN {
    >> my %const = map {chomp; (split)[1,2]; }
    >> qx{ grep '^#define' /path/to/*.h };
    >> my $code;
    >> while ( my($k,$v) = each %const ) {
    >> $code .= "$k => $v,";
    >> }
    >> eval "use constant {$code}";
    >> die $@ if $@;
    >> }


    [...]

    > You also don't need the eval, constant.pm also works with anonymous
    > hashes


    This statement doesn't exactly make any sense :). But the eval isn't
    needed, one way to accomplish the same would be

    ----------------
    BEGIN {
    my %c = ( A => 1, B => 2 );

    use constant;
    constant->import(\%c);
    }

    print A,B,"\n";
     
    Rainer Weikusat, Jul 6, 2013
    #10
  11. Ben Morrow <> writes:
    > Quoth Charles DeRykus <>:
    >> On 7/2/2013 11:05 PM, Ivan Shmakov wrote:
    >> > Is there an easy way to make a bunch of C constants (as in:
    >> > #define) available as Perl subroutines (just like, e. g., POSIX
    >> > does for the errno.h constants)?

    >>
    >> Could you just transform 'em to perl constants, eg,
    >>
    >> BEGIN {
    >> my %const = map {chomp; (split)[1,2]; }
    >> qx{ grep '^#define' /path/to/*.h };
    >> my $code;
    >> while ( my($k,$v) = each %const ) {
    >> $code .= "$k => $v,";
    >> }
    >> eval "use constant {$code}";
    >> die $@ if $@;
    >> }

    >
    > That's what h2ph does. There's a reason it was replaced with h2xs, and
    > that is that it's usually better to get the C compiler to interpret C,
    > since include files can contain all sorts of rubbish.


    h2xs doesn't use external programs for analysing C headers, it
    just contains a more complete 'C header analyzer' than the one in the
    example above (as does h2ph, FWIW).
     
    Rainer Weikusat, Jul 6, 2013
    #11
  12. On 7/6/2013 6:03 AM, Ben Morrow wrote:
    >
    > Quoth Charles DeRykus <>:
    >> On 7/2/2013 11:05 PM, Ivan Shmakov wrote:
    >>> Is there an easy way to make a bunch of C constants (as in:
    >>> #define) available as Perl subroutines (just like, e. g., POSIX
    >>> does for the errno.h constants)?

    >>
    >> Could you just transform 'em to perl constants, eg,
    >>
    >> BEGIN {
    >> my %const = map {chomp; (split)[1,2]; }
    >> qx{ grep '^#define' /path/to/*.h };
    >> my $code;
    >> while ( my($k,$v) = each %const ) {
    >> $code .= "$k => $v,";
    >> }
    >> eval "use constant {$code}";
    >> die $@ if $@;
    >> }

    >
    > That's what h2ph does. There's a reason it was replaced with h2xs, and
    > that is that it's usually better to get the C compiler to interpret C,
    > since include files can contain all sorts of rubbish.
    >
    > For instance, your code above will fail on both these common cases:
    >


    I knew (and have experienced) h2ph's flaws. Somehow, I was thinking
    they were well-behaved, home-grown header files so "I came, I saw,
    I re-invented" h2ph.

    --
    Charles DeRykus
     
    Charles DeRykus, Jul 6, 2013
    #12
  13. On 7/6/2013 5:14 AM, Rainer Weikusat wrote:
    > Rainer Weikusat <> writes:
    >> Charles DeRykus <> writes:

    >
    > [...]
    >
    >>> BEGIN {
    >>> my %const = map {chomp; (split)[1,2]; }
    >>> qx{ grep '^#define' /path/to/*.h };
    >>> my $code;
    >>> while ( my($k,$v) = each %const ) {
    >>> $code .= "$k => $v,";
    >>> }
    >>> eval "use constant {$code}";
    >>> die $@ if $@;
    >>> }

    >
    > [...]
    >
    >> You also don't need the eval, constant.pm also works with anonymous
    >> hashes

    >
    > This statement doesn't exactly make any sense :). But the eval isn't
    > needed, one way to accomplish the same would be
    >
    > ----------------
    > BEGIN {
    > my %c = ( A => 1, B => 2 );
    >
    > use constant;
    > constant->import(\%c);
    > }
    >
    > print A,B,"\n";
    >


    Thanks, I had forgotten that too...

    --
    Charles DeRykus
     
    Charles DeRykus, Jul 6, 2013
    #13
  14. Ivan Shmakov

    Ivan Shmakov Guest

    >>>>> Rainer Weikusat <> writes:
    >>>>> Ben Morrow <> writes:


    [...]

    >> There's a reason [h2ph] was replaced with h2xs, and that is that
    >> it's usually better to get the C compiler to interpret C, since
    >> include files can contain all sorts of rubbish.


    > h2xs doesn't use external programs for analysing C headers, it just
    > contains a more complete 'C header analyzer' than the one in the
    > example above (as does h2ph, FWIW).


    I guess the point was that h2xs (or, rather, WriteConstants ())
    uses the C compiler to get the /values/ of such constants.

    And as for the names, -- indeed.

    --
    FSF associate member #7257
     
    Ivan Shmakov, Jul 6, 2013
    #14
  15. On 7/6/2013 12:04 PM, Ben Morrow wrote:
    >
    > Quoth Rainer Weikusat <>:
    >>
    >> BEGIN {
    >> my %c = ( A => 1, B => 2 );
    >>
    >> use constant;
    >> constant->import(\%c);
    >> }

    >
    > ...
    >
    > You can even calculate the contents of the hashref dynamically, if you
    > like:
    >
    > use constant {
    > map (chr(ord("@") + $_), $_), 1..4,
    > };
    >
    > This expression is evaluated at compile time, so any subs called need to
    > be available at the point where the 'use' statement is compiled.
    >


    Hm, appears not:

    $ perl -le 'use constant {map( (chr(ord("@") + $_), $_), 1..4 ) }'
    syntax error at -e line 1, near "use constant {


    Interestingly though:

    $ perl -le 'use constant map( (chr(ord("@") + $_), $_), 1..4 );
    print A()'
    1B2C3D4

    This works:

    $ perl -le 'BEGIN{%h = map ( (chr(ord("@") + $_), $_), 1..4 ) };use
    constant \%h;print A()'
    1

    This of course too:

    $ perl -le 'use constant; constant->import( {map ( (chr(ord("@") +
    $_), $_), 1..4)}); print A()'
    1

    --
    Charles DeRykus
     
    Charles DeRykus, Jul 6, 2013
    #15
  16. On 2013-07-06 22:33, Charles DeRykus <> wrote:
    > On 7/6/2013 12:04 PM, Ben Morrow wrote:
    >> Quoth Rainer Weikusat <>:
    >>>
    >>> BEGIN {
    >>> my %c = ( A => 1, B => 2 );
    >>>
    >>> use constant;
    >>> constant->import(\%c);
    >>> }

    >>
    >> ...
    >>
    >> You can even calculate the contents of the hashref dynamically, if you
    >> like:
    >>
    >> use constant {
    >> map (chr(ord("@") + $_), $_), 1..4,
    >> };
    >>
    >> This expression is evaluated at compile time, so any subs called need to
    >> be available at the point where the 'use' statement is compiled.
    >>

    >
    > Hm, appears not:
    >
    > $ perl -le 'use constant {map( (chr(ord("@") + $_), $_), 1..4 ) }'
    > syntax error at -e line 1, near "use constant {


    Perl thinks that the { starts a block here, not an anonymous hash. You
    can force it by prepending a +:

    % perl -le 'use constant +{map( (chr(ord("@") + $_), $_), 1..4 ) }; print A, B, C, D'
    1234

    hp

    --
    _ | Peter J. Holzer | Fluch der elektronischen Textverarbeitung:
    |_|_) | Sysadmin WSR | Man feilt solange an seinen Text um, bis
    | | | | die Satzbestandteile des Satzes nicht mehr
    __/ | http://www.hjp.at/ | zusammenpaƟt. -- Ralph Babel
     
    Peter J. Holzer, Jul 7, 2013
    #16
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. RN
    Replies:
    0
    Views:
    2,578
  2. RA Jones
    Replies:
    0
    Views:
    133
    RA Jones
    Aug 18, 2003
  3. Ivan Fomichev

    Force POSIX NFA in Perl?

    Ivan Fomichev, Jul 15, 2005, in forum: Perl Misc
    Replies:
    1
    Views:
    103
    Brian McCauley
    Jul 15, 2005
  4. Peter Makholm

    Substitutions based on Posix ERE's in perl

    Peter Makholm, Apr 5, 2009, in forum: Perl Misc
    Replies:
    1
    Views:
    120
    smallpond
    Apr 6, 2009
  5. PerlFAQ Server
    Replies:
    0
    Views:
    127
    PerlFAQ Server
    Feb 14, 2011
Loading...

Share This Page