Pages: Welcome | Projects

Install some python executables in /usr/libexec

2019/5/6
Tags: [ GNU/Linux ] [ python ] [ rpm ]

Before reading, please note: doing software packaging is a difficult task, and what follows might not follow the best practice (even if it seems to work reasonably well). Asking some experienced packaging person and/or taking examples from existing packages usually pays off. And if there's a better way to do what follows, please drop me an email.

As everybody knows, the setup.py script allows to define a collection of "entry points" for your program, that is commands to install in the PATH (typically /usr/bin/).

Short example, this will install /usr/bin/foo, and have it to execute the main method defined in the bar.bin.foo module:

from setuptools import setup

setup(
    ...
    entry_points={
        'console_scripts' : [
            'foo=bar.bin.foo:main',
        ]
    }
)

A good thing to know is that setuptools allows to specify an alternate path for the entry points, which comes in handy when, for example, one wants to place those binaries in /usr/libexec.

su -c "python setup.py --install-scripts /usr/libexec"

My use case is actually slightly different: I want to do so from a RPM spec file, where the typical pattern is to use py3_build macro. The macro is currently defined as follows (provided by python3-rpm-macros-3-23.el7.noarch):

%py3_install() %{expand:\\\
  CFLAGS="%{optflags}" %{__python3} %{py_setup} %{?py_setup_args} install
  -O1 --skip-build --root %{buildroot} %{?*}
}

The %{?*} syntax is expanding parameters, so I basically want something like this:

%py3_install --install-scripts %{_libexecdir}/%{name}/

But rpm won't really like this thing, as it will try to interpret -- as - (option delimiter) - (option), ending up with this error:

<mock-chroot> sh-4.2# rpm --eval '%py3_install --install-scripts %{_libexecdir}/%{name}/'
py3_install: invalid option -- '-'
error: Unknown option - in py3_install()
\
  CFLAGS="-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions
  -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches
  -m64 -mtune=generic" /usr/bin/python3.6 setup.py  install -O1 --skip-build
  --root /builddir/build/BUILDROOT/%{name}-%{version}-%{release}.x86_64

Thanks to the good people in #fedora-devel (Freenode), I could find the right answer, which afterwards looks so obvious…:

<mock-chroot> sh-4.2# rpm --eval '%py3_install -- --install-scripts %{_libexecdir}/%{name}/'
  \
    CFLAGS="-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions
    -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches
    -m64 -mtune=generic" /usr/bin/python3.6 setup.py  install -O1
    --skip-build --root
    /builddir/build/BUILDROOT/%{name}-%{version}-%{release}.x86_64
    --install-scripts /usr/libexec/%{name}/

Uh, and heads up for this pitfall (driven by inexperience, really): do not use macro with curly brackets %{...}, as this will prevent options from being expanded:

<mock-chroot> sh-4.2# rpm --eval '%{py3_install} -- --install-scripts %{_libexecdir}/%{name}/'
  \
    CFLAGS="-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions
    -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches
    -m64 -mtune=generic" /usr/bin/python3.6 setup.py  install -O1
    --skip-build --root
    /builddir/build/BUILDROOT/%{name}-%{version}-%{release}.x86_64
     -- --install-scripts /usr/libexec/%{name}/