slashpackage is an idea for package management on Unix and Linux systems that was first proposed by Daniel J. Bernstein at the turn of the 21st century. Paul Jarc took the idea and ran with it with a scheme for making everything slashpackage-packaged. For a fair while until around 2014, Laurent Bercot's softwares followed this scheme.
The concept is fairly simple:
Every package is a self-contained directory tree rooted at a particular point.
Those points are well-known places in an enclosing directory structure that encodes package names and versions, and groups packages into collections.
Every package has some standard components in well-known places relative to its root.
A system of symbolic links gives version-independent names for things.
The consequences of the design are severalfold:
side-by-side installation of multiple package versions simultaneously
The naming convention of the enclosing directory structure is such that one can have (say) djbwares-4
installed alongside djbwares-7
.
canonical names
Versioned names are stable.
For example: admin/djbwares-4/command/dnscache
is always the path from the package root to the (compiled) dnscache
command in version 4 of the djbwares package.
simple package addition and removal
Since it is a self-contained directory tree, removing a package is as simple as rm -r
of its root, and adding a package is as simple as unpacking an archive file into the root.
You may have come across many of these ideas in different forms.
A Debian source package is a self-contained directory tree with well-known internal components in standard places. (There is no well-defined outer directory hierarchy, however, or indeed any suggestion of a conventional place for it. Nor do packaged binaries and data files, built from the source, themselves adhere to a self-contained directory tree structure.)
The NetBSD, FreeBSD, and OpenBSD ports trees under /usr/ports
have similar outer directory structures with package groupings such as archivers/
, editors/
, devel/
and so forth.
(They generally do not employ side-by-side version installation, however.)
FTP archive sites, like the Hobbes FTP site run by New Mexico State University, curated packages into collections with similar directory structures.
The Hobbes FTP one, for example, has groupings such as apps/calendar
, dev/rexx
, util/network/tcpip
, and info/newsltr/edm
.
(But packages were of course archive files, not directory trees, and the archive files did not themselves employ this mechanism internally, when unpacked.)
Various commercial Unices such as Solaris and AIX had a similar directory hierarchy under /opt
.
(It was generally less useful because it was largely geared towards corporations and excluded use by people who did not have stock market ticker names or own long-term stable public domain names.)
The one major problem with slashpackage was that the central authority over the outer directory tree, the package groupings and the package basenames, was to most of the world some arbitrary stranger on another continent. That could have been ameliorated, though, by simply adopting (say) the NetBSD naming hierarchy or the FreeBSD naming hierarchy. (Ironically, that would still have been arbitrary strangers on another continent. It is just that the arbitrary strangers would have seemed more authoritative, ironically in part due to their largely faceless natures. Such is human psychology.)
There are various standard components to a package, in well-known locations in every package's directory tree. Some were documented by M. Bernstein on xyr WWW pages; some others can be inferred from the structure of M. Bernstein's published slashpackage-format packages.
package/
The subdirectory that holds all of the files and directories dealing with building the package and package management.
package/compile
An executable (binary or script) that builds the binary form of the package from the source form.
Usually this makes use of helper executables named package/prepare
, package/make
, and package/makeinstall
; but these are less conventional and may not exist in these forms.
package/sharing
A text file for informing a package manager which parts of the package tree are shareable across a group of (identical) machines, universally shareable across any machines, or specific to a single machine.
package/versions
A text file for informing a package manager which versions of the package name are older than this, allowing arbitrary version suffix orderings.
package/upgrade
An executable (binary or script) that makes the versionless name point to this version of the package, that must only be run after the binary form has been built.
Further inferred components are less universal.
package/run
An executable (binary or script) that enables running whatever services the package comprises. Laurent Bercot recommended against this because "it is up to the system administrator to set up the services as he sees fit, and to know exactly what steps should be taken on his system for everything to work as expected". In fact, system administrators usually rely upon packages to provide exactly such utility scripts for dealing with services, user accounts, data directories, log directories, ACLs, and suchlike.
The problem with this is actually that it isn't a very good mechanism because it is woefully incomplete.
Fully-fledged package management systems provide for a whole suite of scripts that set up and tear down the various things that a package needs, not just one script that sets things up and nothing at all for doing the reverse.
They generally have mechanisms, so called "maintainer scripts" in Debian terminology, comprising both "before" and "after" scripts for installation, removal, and upgrade.
Or (like the old BSD pkg
system) they have descriptive "manifests" that declare things like lists of directories, services, and user accounts.
package/install
An executable (binary or script) equivalent to package/compile && package/upgrade
.
package/files
A manifest of the source files in the package.
package/commands
A manifest of the commands in the package.
package/README
The "read me" text file for the package.
Locations for some other well-known components, not particularly standardized but generally good ideas nonetheless, are:
source/
(or src/
)The subdirectory that holds all of the source files and directories.
build/
(or compile/
)The subdirectory used by package/compile
as a work area to build the package from source.
command/
(or bin/
)An output directory where package/compile
places the built executable commands.
manual/
(or man/
)An output directory where package/compile
places the built manual pages.
config/
An output directory where package/compile
places the built configuration files and directories.
library/
(or lib/
)An output directory where package/compile
places the built statically-linked and dynamically-linked function libraries.
include/
An output directory where package/compile
places the built header files for a C, C++, Objective C, or Objective C++ language API.
package/clean
An executable (binary or script) that removes the build work area but leaves the built output areas.
package/distclean
An executable (binary or script) that removes the build work area and the built output areas.
package/compile
As mentioned, building the package is the task of the package/compile
program.
There are various guarantees required of the build process.
The source/
and package/
subtrees are not written-to by a build.
They can potentially, after all, be stored on remote network volumes shared by multiple machines, or on read-only storage media.
The build/
directory may not exist.
Cleaning the build entails simply removing the entire work directory, after all.
One of the tasks of the package/compile
command is to "prepare" the work area, which for starters means creating the directory if it does not exist.
The source/
subtree is linked into the build/
subtree.
This is another of package/compile
's preparatory tasks.
It is done either with symbolic links, if the twain are on distinct volumes (as will definitely be the case if the source/
subtree is on read-only storage media, because the work area has to be read-write), or with ordinary links if they are on the same volume as each other.
The final output files built in the work area are not linked into the output directories, but copied to new files. Re-building the package a second time must not render executables and other generated files in the output directories into a half-completed state. They could, after all, be in use as the package is being re-built from source.
The output directories are updated atomically. This is for the same reasons that work area files are copied and not linked: even the act of copying yields a file that is partly complete during a small window of opportunity. Files and directories are copied to temporary names in the output trees, and then atomically renamed into their final places.
Once one has built a slashpackage package natively, with package/compile
, one can of course convert it into one or more native binary packages for an operating system's package manager with ease.
Most package managers work with the idea that packages are built from source into an output area, staged from that output area into a staging area that represents the final file and directory layout to be packaged up, and then packaged up into packages with accompanying manifests and control information.
This matches the aforementioned slashpackage build system.
package/stage
A handy idea for this is a package/stage
tool.
This is an executable with the responsibility of taking the slashpackage output directories and copying (or linking) the files into a staging area with the final file and directory layouts for one or more binary packages.
This is work that is largely independent of the actual package managers' build tools, as like package/compile
it is a step in the process that is common to most package building procedures for most operating systems' package management mechanisms.
(See the Staging chapter of the FreeBSD Porters' Handbook for example, or the package
function of the Arch PKGBUILD system.)
The package/stage
tool is independent of the package manager, but does have to vary by operating system.
It usually has to incorporate operating system differences such as the locations of directories such as /sbin
and /bin
and whether operating systems prefer packages to install to /usr
or to /usr/local
.
This can be done by checking the output of the uname
utility or the contents of the /etc/os-release
file in the well-known and usual ways, of course.
package/debian
convention
One handy convention in this regard is the package/debian
convention.
Debian packaging tools have the convention of placing the staging areas, intermediate, and control files into a debian/
subtree.
Of course, the process of building a package fills this tree with all sorts of intermediate stuff, that is all mixed up with the initial, static, control and data files used in the packaging process.
The package/debian
convention is that package/debian/
is a read-only image for debian/
, used to initially populate it much like source/
is used to initially populate build/
.
An initial build step is thus to do an analogous task to that of package/prepare
, symbolically linking or ordinarily linking the contents of package/debian/
into debian/
.
Thus the contents of package/debian/
contain the conventional Debian control files mentioned in the Debian Policy Manual and the Debian Maintainers' Guide (and hence described only very briefly here).
package/debian/rules
A Debian rules file.
This makes use of package/compile
for its build
action, and a package/stage
(or similar) command for its binary
action.
package/debian/copyright
Debian-standard machine-parseable copyright information.
package/debian/control
Debian-standard package meta-information.
package/debian/changelog
Debian-standard package change log, which can (only when hard linked as debian/changelog
) be manipulated with Debian's dch
utility.
One way to do this is with a program named package/debian/prepare
.
The build procedure for a Debian package thus is package/debian/prepare && dpkg-buildpackage -uc -b
and the procedure for (say) incrementing the Debian version number is package/debian/prepare && dch -i
.
Another way, if one is a Debian Maintainer, is to make a debian/
directory that is (as source packaged) a symbolic link farm pointing into package/debian/
as required and package that as the packagename_version.debian.tar.gz
overlay archive that accompanies the source archive.
PKGBUILD
Similar ideas can be employed for, say, the Arch PKGBUILD system.
The prepare
function runs package/arch/prepare
, equivalent to package/debian/prepare
; the build
function runs package/compile
and package/stage
; and the package
function (or package_name
functions) set the metadata and run pax
to image the staged files and directories.
One can even address the FreeBSD/TrueOS packaging system with a similar package/bsd/
subtree.