http://qs321.pair.com?node_id=1150856

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

Thanks for all! It's working now, i just needed to replacing __END__ to __DATA__.

I need to write simple script, which calling functions from two modules (one of it contains perl code and another contains c code), measuares the time of each and if they calculation results are equals printing time differences of calulation. Problem is that when i include module with c code and run main script perl says: "readline() on unopened filehandle DATA at C:/other_perl/Strawberry/perl/site/lib/Inline.pm line 360. Use of uninitialized value $data in substitution (s///) at C:/other_perl/Strawberry/perl/site/lib/In line.pm line 360. Use of uninitialized value $data in split at C:/other_perl/Strawberry/perl/site/lib/Inline.pm line 3 61. No source code in DATA section for Inline 'C' section. at optest.pl line 0. INIT failed--call queue aborted. One or more DATA sections were not processed by Inline." Here is the main script:

use Time::HiRes qw(gettimeofday tv_interval); use Test::More; use perl_calc; use c_calc; $start_time_c = [ gettimeofday ]; $c_calc = c_calc::calc_pi(); $end_time_c = [ gettimeofday ]; $elapsed_c = tv_interval($start_time,$end_time); $start_time_perl = [ gettimeofday ]; $perl_calc = perl_calc::calc_pi(); $end_time_perl = [ gettimeofday ]; $elapsed_perl = tv_interval($start_time,$end_time); $differences = abs($elapsed_perl - $elapsed_c); if(ok($c_calc == $perl_calc, "Pi number calc")) { print "C computation time = $elapsed_c\n"; print "Perl computation time = $elapsed_perl\n"; print "Differences = $differences\n"; } done_testing;

Here is module with c code:

package c_calc; use Inline 'C'; 1; __END__ __C__ double my_abs(double num) { return (num > 0)? num : -num; } double calc_pi() { double real_pi = 3.14159265358979; double my_pi = 0; double step_sign = 1; unsigned long long i = 1; while(my_abs(real_pi - my_pi) > 0.00000001) { my_pi += 4.0/i * step_sign; step_sign *= -1; i += 2; } return my_pi; }

I read Inline::C-Cookbook, but i didn't find an answer there. So what i do wrong?

Replies are listed 'Best First'.
Re: Using module with c code in perl program.
by stevieb (Canon) on Dec 21, 2015 at 17:49 UTC
    Update: read Re: Using module with c code in perl program. by AnonyMonk, as that post contains the full explanation straight from the docs. /update.

    I haven't coded in C in many years, and I've never used Inline::C ever, but I took a stab. When I simplify your C code, then change __END__ to __DATA__ in the module, I can get the C to compile, and things *appear* to work correctly. eg:

    Module:

    package c_calc; use Inline C; 1; __DATA__ __C__ int test(int num){ return num; }

    Script:

    use warnings; use strict; use lib '.'; use c_calc; my $num = c_calc::test(5); print $num;

    Might be worth a try. Let us know if it works or not, as inevitably, one or more of the Inline experts will be around eventually.

      Replacing __END__ to __DATA__ working, thanks a lot!

      I've used Inline::C with success and it works under Win32 too.

        I can't confirm for sure because I was only reading into the error message OP was getting, but none of the examples I found online showed using Inline::C within a module, so I traded __END__ for __DATA__ which the error clearly stated it was looking for, and I suspect the module close was causing the grief.

        I'm hoping one of the experienced Inline Monks has run into this before, and can clarify. My test was literally just a guess and some playing :) On Windows, I'd think that one would need to install a C compiler (unless ActiveState and/or Strawberry come with one build-in).

        Update: read Re: Using module with c code in perl program. by AnonyMonk, as my suspicions regarding end-of-module are definitely confirmed by the documentation, per that post.

Re: Using module with c code in perl program.
by scorpio17 (Canon) on Dec 21, 2015 at 19:57 UTC
    In the perl portion, I think this line:
    $elapsed_c = tv_interval($start_time,$end_time);
    should be this:
    $elapsed_c = tv_interval($start_time_c,$end_time_c);
    and
    $elapsed_perl = tv_interval($start_time,$end_time);
    should be:
    $elapsed_perl = tv_interval($start_time_perl,$end_time_perl);
    Note that $start_time and $end_time are never declared, nor initialized, and a "use strict;" at the top would have helped you spot this.

      Really this is mistake, thanks.

Re: Using module with c code in perl program.
by Anonymous Monk on Dec 21, 2015 at 20:10 UTC
    You should read the documentations of Inline itself:
    In case you've forgotten, the DATA pseudo file is comprised of all the text after the __END__ or __DATA__ section of your program. If you're working outside the main package, you'd best use the __DATA__ marker or else Inline will not find your code.
    perldata might also be of interest:
    For compatibility with older scripts written before __DATA__ was introduced, __END__ behaves like __DATA__ in the top level script (but not in files loaded with "require" or "do") and leaves the remaining contents of the file accessible via "main::DATA".
    use says:
    use Module LIST... is exactly equivalent to
    BEGIN { require Module; Module->import( LIST ); }
    except that Module must be a bareword.
      Awesome. I was hoping for a proper explanation.
Re: Using module with c code in perl program.
by Don Coyote (Hermit) on Dec 21, 2015 at 22:19 UTC

    Attempting to place the C code as a string directly into the benchmarking script, a new error was produced.

    So it may be that there needs to be some further modules installed for Strawberry Perl to use Inline.pm with C.

    Replacing END with DATA unfortunately still produces the original Error. I tried to open Inline::DATA as a file handle, but I couldn't quite apply IO calls to pseudo Handles. Also tried various permutations of the examples on C-PAN and in the Cookbook. See below for Code which produced new error. Also note Inline::Files did not install when I ran the cpan install Inline cmd

    Frustratingly, when no use of the DATA symbol occurs there are still attempts to read the unopened handle. Hope this helps progress the issue. DC.

      Out of curiosity, does quoting the requirement of Inline help? ie. use Inline 'C' ... I don't have access to Windows at the moment, so I can't test.

      For that matter, kind of goes without saying, but you can compile a C program outside of Perl in your setup, yes?

        the quoting does not make a difference. from the docs there are various ways of getting the code in. The problem seems to be more that the DATA handle is being read without being opened first.

        inside Inline, c_calc::DATA is aliased into Inline::DATA, and then read in after requiring Socket, but this is used just for CR and LF definitions. I hardcoded those definitions and commented out the Socket require, to no effect. then the subroutines goes on to read-in the aliased Inline::DATA. (my $data = <Inline::DATA>) =~ s/$CR?$LF/\n/g;

        I can compile a C program, using the gcc compiler which comes with Strawberry, I did so to ensure the C code was running before attempting to inline. This would indicate that I already have C compatibility from Strawberry, which makes the "not understanding C language" error contradictory.

      Also note Inline::Files did not install when I ran the cpan install Inline cmd
      Did you actually install Inline::C, or just Inline (without ::C)?

        Ok, promising start, but then failed

        Inline::C was not installed. I installed Inline::C and the script with the code worked. I then tested the script with the C code in the module and that worked, firstly with the Test::More module being used, and then without the ok routine, and it worked. But then it did not continue to work.

        I'm just trying to recreate this now.

        ...

        The script with the Inline code embedded runs whether Testing is active or not.

        The Module import still does not open the DATA filehandle. Stepping through in db, Inline calls init which calls read_DATA, which requires Socket, so it jumps between Strict, Socket, Exporter, and XS_Loader. Then attempts the read on the unopened DATA filehandle.

        At this point I need to look a bit further in detail as to what is happening.

        For some reason there is an error when i tried to install Inline::C both on Ubuntu and Windows. So i was sent portable perl version with preinstalled Inline::C.