2

I have a perl script that I want to be usable on systems with no perl interpreter installed (like a linux container, for example). I generate a binary with PAR::Packer and everything appears to work great.

[0] [ishpeck@centbox03 /tmp/examply]$ file ./perlthing/scripts/hello.pl
./perlthing/scripts/hello.pl: Perl script, ASCII text executable
[0] [ishpeck@centbox03 /tmp/examply]$ cat ./perlthing/scripts/hello.pl
#!/usr/bin/perl
use strict;
use warnings;
use File::Basename;

print "Hello, world!\n"
[0] [ishpeck@centbox03 /tmp/examply]$ cat Makefile
CURDIR=/tmp/examply
TOPDIR=$(CURDIR)/packaging

rpm: perlbin
    sh -c 'for x in packaging/BUILD packaging/RPMS/x86_64 packaging/RPMS/x86 packaging/RPMS/arm packaging/SOURCES packaging/SPECS packaging/SRPMS; do mkdir -p $$x; done'
    rpmbuild --target x86_64 -bb $(TOPDIR)/SPECS/mypackage.spec --define '_topdir $(TOPDIR)' --define '_arch x86_64' --define '_working_dir $(CURDIR)'

perlbin: perlthing/binaries/hello.pl

perlthing/binaries/hello.pl: perlthing/scripts/hello.pl Makefile
    /usr/local/bin/pp -M File::** -M PAR:: --clean --verbose=2 --output=$@ $<

clean:
    rm perlthing/binaries/hello.pl

[0] [ishpeck@centbox03 /tmp/examply]$ make perlbin >/dev/null ; echo $?
0
[0] [ishpeck@centbox03 /tmp/examply]$ file perlthing/binaries/hello.pl
perlthing/binaries/hello.pl: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=7d5b38a792018d0202a96ce8645b00591e7ea7c5, stripped
[0] [ishpeck@centbox03 /tmp/examply]$ ./perlthing/binaries/hello.pl
Hello, world!

So far, so good. It even works when I copy the binary to a machine with no perl interpreter:

core@CoreOS-1 ~ $ which perl
which: no perl in (/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/opt/bin)
core@CoreOS-1 ~ $ ./hello.pl
Hello, world!

I want to package this in an RPM:

[0] [ishpeck@centbox03 /tmp/examply]$ cat packaging/SPECS/mypackage.spec
Name:           ishy-mypackage
Version:        0.1
Release:        1%{?dist}
Summary:        My example package

License:        MIT
URL:            http://ishpeck.net

%description
This is my example package that includes a perl script bundled as a binary via PAR::Packer

%prep
echo "Prepare scriptlet is empty"

%build
echo "Nothing really to do"

%install
rm -rf $RPM_BUILD_ROOT
mkdir -p $RPM_BUILD_ROOT/usr/local/bin/
cp %{_working_dir}/perlthing/binaries/hello.pl $RPM_BUILD_ROOT/usr/local/bin/

%files
/usr/local/bin/hello.pl
[0] [ishpeck@centbox03 /tmp/examply]$ grep rpmbuild Makefile
        rpmbuild --target x86_64 -bb $(TOPDIR)/SPECS/mypackage.spec --define '_topdir $(TOPDIR)' --define '_arch x86_64' --define '_working_dir $(CURDIR)'
[0] [ishpeck@centbox03 /tmp/examply]$ make 

But when I install the package, the perl binary doesn't work anymore!

[0] [ishpeck@centbox03 /tmp/examply]$ sudo rpm -i ./packaging/RPMS/x86_64/ishy-mypackage-0.1-1.el7.x86_64.rpm
[0] [ishpeck@centbox03 /tmp/examply]$ which hello.pl
/usr/local/bin/hello.pl
[0] [ishpeck@centbox03 /tmp/examply]$ hello.pl
Usage: /usr/local/bin/hello.pl [ -Alib.par ] [ -Idir ] [ -Mmodule ] [ src.par ] [ program.pl ]
/usr/local/bin/hello.pl [ -B|-b ] [-Ooutfile] src.par
Removing files in "/tmp/par-6973687065636b/temp-51174"
Undefined subroutine &File::Find::finddepth called at -e line 11.
END failed--call queue aborted at -e line 616.

I don't assume this is a problem with the way I'm using pp to generate the binary because it seems to work everywhere if I just copy it directly. My brain wants to place the blame on (how I use) rpmbuild but I don't even know where to begin with this.

Is there some arcane detail about rpmbuild that I'm missing here?

1
  • Can you run md5sum on the binary before and after it is in the rpm? If they're the same then we should look at what made it into the rpm.
    – chicks
    Mar 12, 2019 at 13:07

1 Answer 1

1

rpmbuild is stripping it

The default rpmbuild macros include strip commands that interfere with whatever magic PAR::Packer is doing.

If it take your sources I can reproduce the problem on CentOS 7, perl v5.16.3. Adding this at the top of your spec:

%global __os_install_post %{nil}

the binaries in the buildroot are unmodified and the program works. I'm not entirely sure why, you may want to ask Perl rpm maintainers or other Perl hackers for details.


Performance sidebar

I notice a consistent 100x slowdown of the packed binary compared to an actual perl interpreter. The difference may be less significant for non-trivial programs. Even this trivial build is 4 MB in size.

I can appreciate bringing the power of the Swiss-Army chainsaw to unenlightened distros, but note that a native binary is unlikely to be a performance boost.

1
  • Thanks for the heads-up. Performance isn't an issue for this particular project. The scripts are going to be only run once for setup and never again so I don't mind if it goes from ten milliseconds to one second execution time.
    – Ishpeck
    Mar 12, 2019 at 17:11

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .