Stage Directory support for ports

The stage directory support means that a port does not install directly into the destination directories, but instead into a separate directory (automake packages call this DESTDIR) from which the package is then built - in many cases, this does not require root privileges. If enabled for a port, the package is first built, installed into the STAGEDIR, packaged, and then installed from the package. If disabled, the traditional approach is used, which means to install directly into the destination and build the package from there.

Convert a port to Stage

List of information to know to be able to convert a port.

Makefile {pre,do,post}-install: targets

@exec, @unexec ordering in pkg-plist

PORTDOCS PORTEXAMPLES

make makeplist

The above command should help preparing plist now that you are staged.

Package as an unprivileged user

Make sure you tested make package as a normal user (not root). If that fails, add NEED_ROOT=yes in the port's Makefile.

Python scripts reference work or stage directory (in a complaint from the staging Q/A checks)

If this happens when the upstream software you are packaging claims DESTDIR support, it is broken (Mailman up to 2.1.16, for instance).

Barring upstream fixes, you can work around the problem, and recompile scripts like this, for instance, from a post-build: target. Assuming your Python scripts are supposed to reside in ${PYTHONPREFIX_SITELIBDIR} after installation:

        (cd ${STAGEDIR}${PREFIX} \
            && ${PYTHON_CMD} ${PYTHON_LIBDIR}/compileall.py \
            -d ${PYTHONPREFIX_SITELIBDIR} -f ${PYTHONPREFIX_SITELIBDIR:S;${PREFIX}/;;})

This runs a compilation on a path relative to the stage directory (based on the cd ${STAGEDIR}${PREFIX} part), and prefixes the ${PYTHONPREFIX_SITELIBDIR} to the file name recorded in the byte-compiled output file (through the -d ${PYTHONPREFIX_SITELIBDIR}). -f is required to force recompilation, and the :S;${PREFIX}/;; is to strip the prefix from the PYTHONPREFIX_SITELIBDIR variable to make it a path relative to ${PREFIX}.

TIPS and TRICKS

Confirming your StageDir conversion work

p5-* pkg-plist and MAN

For p5-ports which previously use MAN3 you can use macro PERL5_MAN3 inside pkg-plist. For example: lib/perl5/5.14/man/man3/AnyEvent::I3.3.gz can be replaced with %%PERL5_MAN3%%/AnyEvent::I3.3.gz

@cwd

/!\ Beware: pkg_install is buggy when handling "@cwd", if your ports have "@cwd" in the plist it needs to be changed to the actual directory. Using @cwd %%PREFIX%% will not work as it is already in PLIST_SUB as PREFIX=%D.

A workaround is to use PLIST_SUB+=RESETPREFIX=${PREFIX} in Makefile and then use @cwd %%RESETPREFIX%% in pkg-plist.

META ports

Please add NO_MTREE=yes on meta ports. Otherwise, they would needlessly extract the mtree to the stage dir, and be counted as orphans.

Kernel module ports

Ports that install kernel modules (usually in /boot/modules) can add USES=kmod to Makefile to have most items taken care of.

ranlib error (permission denied)

Makefile.in created with old automake runs ranlib twice, when building the library and when installin (on our case, staging), and because of that you can see errors like these:

Making install in lib
/bin/sh ../mkinstalldirs .../work/stage/usr/local/lib
 install   -m 444 libft.a .../work/stage/usr/local/lib/libft.a
 /usr/local/bin/ranlib .../work/stage/usr/local/lib/libft.a
/usr/local/bin/ranlib: unable to copy file '.../work/stage/usr/local/lib/libft.a'; reason: Permission denied

A workaround to get it fixed is to add a REINPLACE_CMD on post-patch: target to remove RANLIB from installation, like this:

        @${REINPLACE_CMD} -e '/echo.*RANLIB/,+1d' \
                ${WRKSRC}/lib/Makefile.in

Known problems

ports/StageDir (last edited 2014-04-15 18:50:36 by BryanDrewery)