Welcome! Log In Create A New Profile

Advanced

Perl Inline C code inside nginx Perl module

Posted by Ondrej Jombik 
Ondrej Jombik
Perl Inline C code inside nginx Perl module
April 13, 2018 02:50AM
We have some proprietary code in C language, which we cannot convert
into Perl. We would like to use this C code in Perl nginx module. Code
runs well under Perl's Inline C.

However when I try to run Inline C code in nginx Perl module, it does
not work. Not only this code does not work, in fact no Inline C code
work inside Perl nginx environment.

For example, look at this very simple Perl module inlinetest.pm:

package inlinetest;
use strict;
use nginx;

$ENV{'PATH'} = '/bin/:/usr/bin/';
use Inline Config =>
DIRECTORY => '/tmp/';
use Inline "C" => <<'...';
void test_fnc(int num)
{
fprintf(stderr, "%d\n", num);
}
....

sub handler {
$request->send_http_header('text/html');
return OK;
}

1;

Related nginx configuration is pretty standard:

perl_modules /etc/nginx/perl/;
perl_require inlinetest.pm;

server {
listen 127.0.0.1:80;
location /auth {
perl inlinetest::handler;
}
}

As you can see in my example, I am not even using or calling test_fnc()
yet. But Perl code simply fails on startup with this error message:

-- Unit nginx.service has begun starting up.
nginx[20011]: nginx: [emerg] require_pv("inlinetest.pm") failed: "Running Mkbootstrap for inlinetest_0cff
nginx[20011]: chmod 644 "inlinetest_0cff.bs"
nginx[20011]: "/usr/bin/perl" "/usr/share/perl/5.24/ExtUtils/xsubpp" -typemap "/usr/share/perl/5.24/ExtUt
nginx[20011]: x86_64-linux-gnu-gcc -c -I"/" -D_REENTRANT -D_GNU_SOURCE -DDEBIAN -fwrapv -fno-strict-alias
nginx[20011]: x86_64-linux-gnu-gcc: error trying to exec 'cc1': execvp: No such file or directory
nginx[20011]: Makefile:332: recipe for target 'inlinetest_0cff.o' failed
nginx[20011]: make: *** [inlinetest_0cff.o] Error 1
nginx[20011]: A problem was encountered while attempting to compile and install your Inline
nginx[20011]: C code. The command that failed was:
nginx[20011]: "make > out.make 2>&1" with error code 2
nginx[20011]: The build directory was:
nginx[20011]: /tmp/build/inlinetest_0cff
nginx[20011]: To debug the problem, cd to the build directory, and inspect the output files.
nginx[20011]: at /etc/nginx/perl/inlinetest.pm line 10.
nginx[20011]: ...propagated at /usr/share/perl5/Inline/C.pm line 869.
nginx[20011]: BEGIN failed--compilation aborted at /etc/nginx/perl/inlinetest.pm line 10.
nginx[20011]: Compilation failed in require at (eval 1) line 1."
nginx[20011]: nginx: configuration file /etc/nginx/nginx.conf test failed
systemd[1]: nginx.service: Control process exited, code=exited status=1
systemd[1]: Failed to start A high performance web server and a reverse proxy server.
-- Subject: Unit nginx.service has failed

Does anyone has any idea why it fails to run under nginx Perl?

--
Ondrej JOMBIK
Platon Technologies s.r.o., Hlavna 3, Sala SK-92701
+421222111321 - info@platon.net - http://platon.net

Read our latest blog:
https://blog.platon.sk/icann-sknic-tld-problemy/

My current location: Bratislava, Slovakia
My current timezone: +0100 GMT (CET)
(updated automatically)

_______________________________________________
nginx mailing list
nginx@nginx.org
http://mailman.nginx.org/mailman/listinfo/nginx
Maxim Dounin
Re: Perl Inline C code inside nginx Perl module
April 13, 2018 04:10PM
Hello!

On Fri, Apr 13, 2018 at 02:40:17AM +0200, Ondrej Jombik wrote:

> We have some proprietary code in C language, which we cannot convert
> into Perl. We would like to use this C code in Perl nginx module. Code
> runs well under Perl's Inline C.
>
> However when I try to run Inline C code in nginx Perl module, it does
> not work. Not only this code does not work, in fact no Inline C code
> work inside Perl nginx environment.
>
> For example, look at this very simple Perl module inlinetest.pm:
>
> package inlinetest;
> use strict;
> use nginx;
>
> $ENV{'PATH'} = '/bin/:/usr/bin/';
> use Inline Config =>
> DIRECTORY => '/tmp/';
> use Inline "C" => <<'...';
> void test_fnc(int num)
> {
> fprintf(stderr, "%d\n", num);
> }

[...]

> As you can see in my example, I am not even using or calling test_fnc()
> yet. But Perl code simply fails on startup with this error message:
>
> -- Unit nginx.service has begun starting up.
> nginx[20011]: nginx: [emerg] require_pv("inlinetest.pm") failed: "Running Mkbootstrap for inlinetest_0cff
> nginx[20011]: chmod 644 "inlinetest_0cff.bs"
> nginx[20011]: "/usr/bin/perl" "/usr/share/perl/5.24/ExtUtils/xsubpp" -typemap "/usr/share/perl/5.24/ExtUt
> nginx[20011]: x86_64-linux-gnu-gcc -c -I"/" -D_REENTRANT -D_GNU_SOURCE -DDEBIAN -fwrapv -fno-strict-alias
> nginx[20011]: x86_64-linux-gnu-gcc: error trying to exec 'cc1': execvp: No such file or directory
> nginx[20011]: Makefile:332: recipe for target 'inlinetest_0cff.o' failed

The problem is that your PATH is empty when relevant compilation
happens. You try to set it in the code using "$ENV{'PATH'} =
....", but it doesn't work as this happens _after_ "use Inline...",
because "use ..." operators are executed at compile time in Perl,
much like BEGIN{}.

A simple fix would be to set PATH in a BEGIN{} block at compile
time:

BEGIN { $ENV{'PATH'} = '/bin/:/usr/bin/'; }
use Inline ...

Alternativel, you can use nginx "env" directive to set PATH or
preserve it from original environment, see http://nginx.org/r/env.

--
Maxim Dounin
http://mdounin.ru/
_______________________________________________
nginx mailing list
nginx@nginx.org
http://mailman.nginx.org/mailman/listinfo/nginx
Ondrej Jombik
Re: Perl Inline C code inside nginx Perl module
April 15, 2018 07:10PM
On Fri, 13 Apr 2018, Maxim Dounin wrote:

>> As you can see in my example, I am not even using or calling test_fnc()
>> yet. But Perl code simply fails on startup with this error message:
>>
>> -- Unit nginx.service has begun starting up.
>> nginx[20011]: nginx: [emerg] require_pv("inlinetest.pm") failed: "Running Mkbootstrap for inlinetest_0cff
>> nginx[20011]: chmod 644 "inlinetest_0cff.bs"
>> nginx[20011]: "/usr/bin/perl" "/usr/share/perl/5.24/ExtUtils/xsubpp" -typemap "/usr/share/perl/5.24/ExtUt
>> nginx[20011]: x86_64-linux-gnu-gcc -c -I"/" -D_REENTRANT -D_GNU_SOURCE -DDEBIAN -fwrapv -fno-strict-alias
>> nginx[20011]: x86_64-linux-gnu-gcc: error trying to exec 'cc1': execvp: No such file or directory
>> nginx[20011]: Makefile:332: recipe for target 'inlinetest_0cff.o' failed
>
> The problem is that your PATH is empty when relevant compilation
> happens. You try to set it in the code using "$ENV{'PATH'} =
> ...", but it doesn't work as this happens _after_ "use Inline...",
> because "use ..." operators are executed at compile time in Perl,
> much like BEGIN{}.
>
> A simple fix would be to set PATH in a BEGIN{} block at compile
> time:
>
> BEGIN { $ENV{'PATH'} = '/bin/:/usr/bin/'; }
> use Inline ...
>
> Alternativel, you can use nginx "env" directive to set PATH or
> preserve it from original environment, see http://nginx.org/r/env.

Thanks Maxim, it worked like a charm.
Your help is very appreciated!

I prefer using BEGIN { $ENV{'PATH'} = ... } construction, because this
will have scope for Perl module only, while nginx "env" directive would
be nginx-wide. Is this assumption correct?

Also here is some unrelated additional info which may be useful for
someone in the future:

If Inine C code is in Perl module and your C code is in __DATA__/__C__
section, using "Inline->init" statement is neccessary. Also trailing
"1;" is important and obviously must be placed before __DATA__.

Example:

package PACKAGENAME;

use strict;
use warnings;
use base qw(Exporter);
use Carp;
use Exporter ();
use Inline 'C' => 'DATA',
name => 'PACKAGENAME';
Inline->init;

use vars qw(@EXPORT @EXPORT_OK %EXPORT_TAGS $VERSION);

$VERSION = do { [ q$Revision: 30336 $ =~ /(\d+)/g ]->[0]; };
@EXPORT = qw( example_function_for_export );
@EXPORT_OK = qw( example_function_for_export );
%EXPORT_TAGS = qw();

1;

__DATA__
__C__

/* here goes your C code */

void example_function_for_export(int num)
{
fprintf(stderr, "%d\n", num);
}

--
Ondrej JOMBIK
Platon Technologies s.r.o., Hlavna 3, Sala SK-92701
+421222111321 - info@platon.net - http://platon.net

Read our latest blog:
https://blog.platon.sk/icann-sknic-tld-problemy/

My current location: Bratislava, Slovakia
My current timezone: +0100 GMT (CET)
(updated automatically)

_______________________________________________
nginx mailing list
nginx@nginx.org
http://mailman.nginx.org/mailman/listinfo/nginx
Maxim Dounin
Re: Perl Inline C code inside nginx Perl module
April 16, 2018 02:40PM
Hello!

On Sun, Apr 15, 2018 at 07:01:42PM +0200, Ondrej Jombik wrote:

> On Fri, 13 Apr 2018, Maxim Dounin wrote:
>
> >> As you can see in my example, I am not even using or calling test_fnc()
> >> yet. But Perl code simply fails on startup with this error message:
> >>
> >> -- Unit nginx.service has begun starting up.
> >> nginx[20011]: nginx: [emerg] require_pv("inlinetest.pm") failed: "Running Mkbootstrap for inlinetest_0cff
> >> nginx[20011]: chmod 644 "inlinetest_0cff.bs"
> >> nginx[20011]: "/usr/bin/perl" "/usr/share/perl/5.24/ExtUtils/xsubpp" -typemap "/usr/share/perl/5.24/ExtUt
> >> nginx[20011]: x86_64-linux-gnu-gcc -c -I"/" -D_REENTRANT -D_GNU_SOURCE -DDEBIAN -fwrapv -fno-strict-alias
> >> nginx[20011]: x86_64-linux-gnu-gcc: error trying to exec 'cc1': execvp: No such file or directory
> >> nginx[20011]: Makefile:332: recipe for target 'inlinetest_0cff.o' failed
> >
> > The problem is that your PATH is empty when relevant compilation
> > happens. You try to set it in the code using "$ENV{'PATH'} =
> > ...", but it doesn't work as this happens _after_ "use Inline...",
> > because "use ..." operators are executed at compile time in Perl,
> > much like BEGIN{}.
> >
> > A simple fix would be to set PATH in a BEGIN{} block at compile
> > time:
> >
> > BEGIN { $ENV{'PATH'} = '/bin/:/usr/bin/'; }
> > use Inline ...
> >
> > Alternativel, you can use nginx "env" directive to set PATH or
> > preserve it from original environment, see http://nginx.org/r/env.
>
> Thanks Maxim, it worked like a charm.
> Your help is very appreciated!
>
> I prefer using BEGIN { $ENV{'PATH'} = ... } construction, because this
> will have scope for Perl module only, while nginx "env" directive would
> be nginx-wide. Is this assumption correct?

No. Changing process environment will change the whole process
environment, regardless of how you do it. But doing this in the
perl code might be the better option since it is closer to the
code which actually needs PATH set.

[...]

--
Maxim Dounin
http://mdounin.ru/
_______________________________________________
nginx mailing list
nginx@nginx.org
http://mailman.nginx.org/mailman/listinfo/nginx
Sorry, only registered users may post in this forum.

Click here to login