Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl: the Markov chain saw
 
PerlMonks  

Using Inline::C in a package

by rem45acp (Novice)
on Sep 04, 2013 at 16:45 UTC ( #1052386=perlquestion: print w/ replies, xml ) Need Help??
rem45acp has asked for the wisdom of the Perl Monks concerning the following question:

I need to be able to call some C functions inside a package that I have wrote. I cannot seem to figure out how to embed the C code in a perl package, as all the examples I can find of Inline::C are just plain old scripts. I have been able to properly link to external C libraries and include header files in a normal script and get it working. Here is what I have so far:
package PIC::DevaSysI2CIO; use strict; use Inline C => Config => LIBS => "-LE:/drivers/usb/devasys_i2cio -lusbi2cio", INC => "-IE:/drivers/usb/devasys_i2cio", BUILD_NOISY => 1; use Inline C; sub new { my ($class_name) = @_; my ($self) = {}; bless($self, $class_name); return $self; } sub open_device { h = openDevice(); } 1; __END__ __C__ #include <windows.h> #include "Usbi2cio.h" HANDLE openDevice() { HANDLE h = INVALID_HANDLE_VALUE; h = DAPI_OpenDeviceInstance("UsbI2cio", 0); return h; }
When I test the package in a separate perl script, I get the following: Bareword "C" not allowed while "strict subs" in use at E:/lib/Perl/lib/PIC/DevaSysI2CIO.pm line 7. Compilation failed in require at E:\sandbox\test.pl line 2. BEGIN failed--compilation aborted at E:\sandbox\test.pl line 2. Thank you.

Comment on Using Inline::C in a package
Download Code
Re: Using Inline::C in a package
by choroba (Canon) on Sep 04, 2013 at 16:53 UTC
    I have no experience with Inline::C, but the following line seems suspicious:
    use Inline C;

    I would say there is a :: missing on line 7.

    Update.
    It works for me if I change it to

    use Inline 'C';

    Note that using the fat comma (=>) automatically quotes the C. This problem only happens under strict.

    لսႽ ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ
      I would say there is a :: missing on line 7.

      No. The OP is exactly correct. That is how Inline C is used. Though it is normal followd by some other arguments; Eg. This is my standard usage:

      #! perl -slw use strict; use Inline C => Config => BUILD_NOISY => 1; use Inline C => <<'END_C', NAME => 'rdtsc', CLEAN_AFTER_BUILD => 0; SV *rdtsc() { return newSVuv( (UV)__rdtsc() ); } ... END_C use Data::Dump qw[ pp ]; use GD; ...

      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".
      In the absence of evidence, opinion is indistinguishable from prejudice.
        OK, I stand corrected. Is the repetition of the use line also demanded?
        لսႽ ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ
        So does the C code go before the package declaration? I'm confused on where the perl methods go before or after the C code.

      To clarify why it's "that way":

      You actually are using Inline, with the C plugin. So "C" is an argument passed to Inline similar to how a function name might be specified in an import list.

      The reason it's often seen "bare" is because it's quite common to do it this way:

      use Inline C => 'DATA'; # ... __DATA__ __C__ /* C code here */

      In which case the "C" is actually quoted by the fat comma (=>) operator.

      Multiple uses of Inline C =>... are common and ok; one is often used to specify configuration settings, while others are used to initiate inline code sequences either via a here-doc or the __DATA__ segment.


      Dave

Re: Using Inline::C in a package
by tobyink (Abbot) on Sep 04, 2013 at 17:13 UTC
    use Inline C;

    ... the "C" here is a bareword, so strict 'subs' doesn't like it. You could drop use strict, or you could quote "C" in single or double quotes...

    use Inline 'C';

    ... or use the magic quoting power of the fat comma...

    use Inline C => ();

    Also, I'm pretty sure you want __DATA__ instead of __END__. __END__ behaves the same as __DATA__ in scripts, but not in modules.

    Personally I don't like the __DATA__ loading bit of Inline::C; I just use:

    use Inline C => q{ /* my C code goes here */ };

    (or heredocs).

    PS: a very simple module using Inline::C is Devel::PL_origargv - take a peek at the source code and let me know if you have any questions about it.

    use Moops; class Cow :rw { has name => (default => 'Ermintrude') }; say Cow->new->name
      Based on all the responses, this is what I have so far. It gets past the build stage, but it complains about no __DATA__ section, and also cannot find the openDevice() function
      package PIC::DevaSysI2CIO; use strict; use Inline C => Config => LIBS => "-LE:/drivers/usb/devasys_i2cio -lusbi2cio", INC => "-IE:/drivers/usb/devasys_i2cio", BUILD_NOISY => 1; use Inline C => q { #include <windows.h> #include "Usbi2cio.h" HANDLE openDevice() { HANDLE h = INVALID_HANDLE_VALUE; h = DAPI_OpenDeviceInstance("UsbI2cio", 0); return h; } }; sub new { my ($class_name) = @_; my ($self) = {}; bless($self, $class_name); return $self; } sub open_device { my $h = openDevice(); } 1;
Re: Using Inline::C in a package
by BrowserUk (Pope) on Sep 04, 2013 at 17:23 UTC

    Whilst multiple use Inline C => ... lines are common a useful; without the C being followed by a fat comma (=>) the C becomes a prohibited bareword. In any case, that second use line with no arguments is redundant.

    Correct that (ie. remove the redundant line) and you'll find your next error:

    C:\test>perl junk.pm Can't modify constant item in scalar assignment at junk.pm line 19, ne +ar ");"

    Which is this line:

    h = openDevice()

    Variables need sigils in Perl.

    Cccorrect that and you're on your own as I don't have the headers or library to try to compile your c code.


    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".
    In the absence of evidence, opinion is indistinguishable from prejudice.
      I have been able to get it to fully compile.
      It croaks if OpenDevice returns a HANDLE, which is
      typedef void* HANDLE;
      But if OpenDevice returns void everything compiles and runs at least.
      Here is the updated code:
      package PIC::DevaSysI2CIO; use strict; use Inline C => Config => LIBS => "-LE:/drivers/usb/devasys_i2cio -lusbi2cio", INC => "-IE:/drivers/usb/devasys_i2cio", BUILD_NOISY => 1; use Inline C => q { #include <windows.h> #include "Usbi2cio.h" #include <stdio.h> void OpenDevice() { HANDLE handle = INVALID_HANDLE_VALUE; handle = DAPI_OpenDeviceInstance("UsbI2cIo", 0); if (handle == INVALID_HANDLE_VALUE) { printf("Could not open device\n"); } else { printf("Opened device!\n"); } } }; sub new { my ($class_name) = @_; my ($self) = {}; bless($self, $class_name); return $self; } sub open_device { OpenDevice(); } 1;

        You'll need to wrap the C handle in a bless reference. See Re^12: odd line in windows for an example.


        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".
        In the absence of evidence, opinion is indistinguishable from prejudice.

        Hi, rem45acp,

        I suggest you use InlineX::C2XS to get the task done with out any annoyance. first: create a test.pl like below:

        use strict; use Inline C => Config => LIBS => "-LE:/drivers/usb/devasys_i2cio -lusbi2cio", INC => "-IE:/drivers/usb/devasys_i2cio", BUILD_NOISY => 1; use Inline C => q { #include <windows.h> #include "Usbi2cio.h" #include <stdio.h> void OpenDevice() { HANDLE handle = INVALID_HANDLE_VALUE; handle = DAPI_OpenDeviceInstance("UsbI2cIo", 0); if (handle == INVALID_HANDLE_VALUE) { printf("Could not open device\n"); } else { printf("Opened device!\n"); } } };
        then run: c2xs ....... it will produce a XS package for you. Please refer Inline::C2XS doc for details.




        I am trying to improve my English skills, if you see a mistake please feel free to reply or /msg me a correction

Re: Using Inline::C in a package
by syphilis (Canon) on Sep 05, 2013 at 12:26 UTC
    cannot seem to figure out how to embed the C code in a perl package

    Incidentally, you can have multiple packages in the one Inline::C script (just as you can with perl scripts):
    package FOO; use Inline C => <<'EOC'; void hello() { printf("Hello from FOO\n"); } EOC package BAR; use Inline C => <<'EOC'; void hello() { printf("Hello from BAR\n"); } EOC package FUBAR; use Inline C => <<'EOC'; void hello() { printf("Hello from FUBAR\n"); } EOC FOO::hello(); BAR::hello(); FUBAR::hello(); hello();
    Which outputs:
    Hello from FOO Hello from BAR Hello from FUBAR Hello from FUBAR
    Cheers,
    Rob

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://1052386]
Front-paged by Arunbear
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others making s'mores by the fire in the courtyard of the Monastery: (6)
As of 2015-07-07 03:07 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    The top three priorities of my open tasks are (in descending order of likelihood to be worked on) ...









    Results (86 votes), past polls