summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorP. J. McDermott <pehjota>2014-09-02 11:27:27 (EDT)
committer P. J. McDermott <pj@pehjota.net>2014-09-02 11:27:27 (EDT)
commit82bd9a68d53946d05ca30fdeae676c2548949820 (patch)
treef2b24406948c96dc20d66a83eb40e263060a7ac0
parenta1f93ac3592df6bbd67cb3b13d04f54f1c2be250 (diff)
doc/pkg/basic-expat: New file
Copied from dev/packaging/tutorials/basic.
-rw-r--r--doc/pkg/basic-expat.mdwn761
1 files changed, 761 insertions, 0 deletions
diff --git a/doc/pkg/basic-expat.mdwn b/doc/pkg/basic-expat.mdwn
new file mode 100644
index 0000000..5d54a73
--- /dev/null
+++ b/doc/pkg/basic-expat.mdwn
@@ -0,0 +1,761 @@
+[[!meta title="Basic Packaging Tutorial"]]
+
+In this introduction to software packaging, we will package the Expat XML parser
+library. This is a pretty simple but complete package, consisting of a shared
+library and its development files plus an executable utility and some
+documentation.
+
+We will use [opkbuild 3.0.x][opkbuild] to build a package in [Source Package
+Format 2.0][spf] (SPF 2.0) with the assistance of [opkhelper 3.0.x][opkhelper].
+
+This tutorial assumes some knowledge of the UNIX shell command language and
+utilities (see the "Shell and Utilities" volume of [POSIX.1-2008][posix]) and at
+least basic familiarity with [makefile syntax][posix-makefile].
+
+This tutorial presents one possible packaging workflow that seems to work well.
+There is no mandatory workflow to packaging. The only requirements are those
+made by the source package format and any build helper utilities that are used.
+
+[opkbuild]: http://git.proteanos.com/opkbuild/opkbuild.git/
+[spf]: http://specs.proteanos.com/spf-2.0/
+[opkhelper]: http://git.proteanos.com/opkhelper/opkhelper.git/
+[posix]: http://pubs.opengroup.org/onlinepubs/9699919799/
+[posix-makefile]: http://pubs.opengroup.org/onlinepubs/9699919799/utilities/make.html#tag_20_76_13
+
+
+Getting Started
+===============
+
+Source Package Directory
+------------------------
+
+First, make a *source package directory*. This is the directory that will
+contain all of our source package files. SPF 2.0 makes no requirements on the
+name of this directory, but using the name of the source package is recommended.
+
+ $ mkdir expat
+ $ cd expat
+
+We need [a file called `format`][spf-format] to identify the format of our
+source package. For SPF 2.0, it should simply contain the string `2.0`.
+
+ $ echo '2.0' >format
+
+Upstream Source Archive
+-----------------------
+
+Obviously we need the source code of the software to be packaged. Go to
+[Expat's Web site][expat], find the expat 2.1.0 archive, and download it into
+the source package directory.
+
+ $ wget 'http://downloads.sourceforge.net/project/expat/expat/2.1.0/expat-2.1.0.tar.gz'
+
+SPF 2.0 requires that an [upstream source archive][spf-upstream-source] be named
+`<pkgname>-<pkgver>.orig.tar<ext>`, where `<pkgname>` is the name of the source
+package, `<pkgver>` is the upstream version of the source package, and `<ext>`
+is an optional file extension to indicate compression. So, rename the archive
+accordingly.
+
+ $ mv 'expat-2.1.0.tar.gz' 'expat-2.1.0.orig.tar.gz'
+
+[spf-format]: http://specs.proteanos.com/spf-2.0/overview.html#files-format
+[expat]: http://expat.sourceforge.net/
+[spf-upstream-source]: http://specs.proteanos.com/spf-2.0/overview.html#files-src-src-ver-tar-ext
+
+
+Source Package Metadata
+=======================
+
+Now we need some metadata for our source package.
+
+Control File
+------------
+
+First we'll make a `control` file. The format of this file is not yet
+documented in the SPF 2.0 specification, but it is documented [in the Debian
+Policy Manual][dpm-control]. The [source package fields][spf-fields-src] are
+`Maintainer` (required), `Build-Depends` (optional), and `Homepage` (optional).
+We'll fill in the fields whose values we know right now: `Maintainer` and
+`Homepage`.
+
+`Maintainer` is the name and e-mail address of the person or team responsible
+for the package (i.e. usually you when you are making a package). The value
+must follow the syntax of the `mailbox` symbol in [RFC 5322 section
+3.4][rfc-5322-3.4]. That is, the value must be of the form `name <address>`.
+If `name` contains any of the following characters, it must be in double quotes:
+
+ ( ) < > [ ] : ; @ \ , .
+
+`Homepage` is the URL of the Web site for the package, if such a site exists.
+
+Our expat `control` file looks like this:
+
+ Maintainer: "J. Random Hacker" <jrandom@example.com>
+ Homepage: http://expat.sourceforge.net/
+
+Change Log
+----------
+
+Now we'll make a `changelog` file. The format of this file is documented [in
+the SPF 2.0 specification][spf-changelog]. We're making version "2.1.0-1" of
+the "expat" source package for the "trunk" distribution. We can get the current
+date and time in the RFC 5322 format using the **date**(1) command:
+
+ $ LC_ALL='POSIX' date '+%a, %d %b %Y %H:%M:%S %z'
+
+Our expat `changelog` file looks like this:
+
+ expat (2.1.0-1) trunk
+
+ * Initial release.
+
+ -- "J. Random Hacker" <jrandom@example.com> Sun, 18 Nov 2012 11:58:19 -0500
+
+
+Building the Software
+=====================
+
+We can now write our `build` makefile to try to get the Expat software to build.
+[The `build` makefile][spf-build] "directs the process of building and
+installing data files to be provided by binary packages".
+
+Looking Through the Source
+--------------------------
+
+With a "[no-op][no-op]" target in `build`, we can make **opkbuild**(1) prepare a
+*[build work area][spf-work-area]* with the unpacked source code and stop. This
+target isn't required by SPF 2.0, but it seems to facilitate a nice workflow.
+So begin writing `build` as follows:
+
+ #!/usr/bin/make -f
+
+ nop:
+ @:
+
+Note that, due to makefile syntax, the line after `nop:` must begin with a tab
+character. This line is called a "command line" in makefile syntax. The [`:`
+utility][posix-colon] is a "null utility" that returns an exit status of zero.
+A command prefix of `@` tells **make**(1) to not write the command to standard
+output before executing it.
+
+The `build` makefile must be executable, so set its file mode:
+
+ $ chmod 755 build
+
+We can now make **opkbuild**(1) prepare our build work area.
+
+ $ opkbuild -b -c -T nop
+
+The options are explained in the help output of opkbuild, obtained by running
+`opkbuild -h`. The `-b` option tells **opkbuild**(1) to build only binary
+packages (no source package). The `-c` option tells it to not clean up the work
+area after building packages. The `-T` option specifies a target to be built
+instead of the standard `build` and `install` targets.
+
+Now look in `tmp/src/`, the location of the source code within the build work
+area.
+
+ $ ls tmp/src/
+
+Look for some documentation file that might tell us how to build Expat. This
+kind of information is usually kept in a file called `INSTALL` or `README`.
+Expat's `README` file says to run `./configure`, then `make` and `make install`.
+
+Looking at `tmp/src/configure`, we see that it is "[g]enerated by GNU Autoconf
+2.68 for expat 2.1.0". The `tmp/src/README` file reports that the makefile
+supports the use of either the `DESTDIR` or `INSTALL_ROOT` macro to install
+Expat somewhere other than in the root of the filesystem. So, we should be able
+to use opkhelper's buildsystem utilities to automatically configure, build, and
+install Expat for us.
+
+Building
+--------
+
+So let's add a `build` target to our `build` makefile. The makefile should now
+look like this:
+
+ #!/usr/bin/make -f
+
+ nop:
+ @:
+
+ build:
+ oh-autoconfigure
+ oh-autobuild
+ touch $@
+
+Read the manual pages and/or source code of **oh-autoconfigure**(1) and
+**oh-autobuild**(1) to learn more about what they do.
+
+The `touch $@` command is recommended by SPF 2.0:
+
+> The build target should create a file named build in the build work area to
+> prevent configuration and compilation from being performed multiple times.
+
+We can now build Expat.
+
+ $ opkbuild -b -c -T build
+
+[dpm-control]: http://www.debian.org/doc/debian-policy/ch-controlfields.html#s-controlsyntax
+[spf-fields-src]: http://specs.proteanos.com/spf-2.0/fields.html#fields-src
+[rfc-5322-3.4]: https://tools.ietf.org/html/rfc5322#section-3.4
+[spf-changelog]: http://specs.proteanos.com/spf-2.0/metadata.html#changelog
+[spf-build]: http://specs.proteanos.com/spf-2.0/buildsys.html#build
+[no-op]: https://en.wiktionary.org/wiki/no-op
+[spf-work-area]: http://specs.proteanos.com/spf-2.0/buildsys.html#work-area
+[posix-colon]: http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#colon
+
+
+Installing the Software
+=======================
+
+We can now finish our `build` makefile to install the Expat software and make
+some binary packages.
+
+Installing
+----------
+
+Add a basic `install` target to the `build` makefile. The makefile should now
+look like this:
+
+ #!/usr/bin/make -f
+
+ nop:
+ @:
+
+ build:
+ oh-autoconfigure
+ oh-autobuild
+ touch $@
+
+ install: build
+ oh-autoinstall
+
+The `install` target is declared as depending on the `build` target:
+
+ install: build
+
+Read the manual page and/or source code of **oh-autoinstall**(1) to learn more
+about what it does.
+
+Install Expat:
+
+ $ opkbuild -b -c -T install
+
+Splitting Files Into Binary Packages
+------------------------------------
+
+Look in the *installation destination directory* `tmp/dest/` for files installed
+by Expat's build system. This can be done with the **find**(1) command, which
+results in the following when building for the `core-linux-eglibc` architecture:
+
+ $ find tmp/dest -exec ls -Fd '{}' ';' | sed 's|^tmp/dest||'
+ /
+ /usr/
+ /usr/bin/
+ /usr/bin/xmlwf*
+ /usr/share/
+ /usr/share/man/
+ /usr/share/man/man1/
+ /usr/share/man/man1/xmlwf.1
+ /usr/lib/
+ /usr/lib/core-linux-eglibc/
+ /usr/lib/core-linux-eglibc/pkgconfig/
+ /usr/lib/core-linux-eglibc/pkgconfig/expat.pc
+ /usr/lib/core-linux-eglibc/libexpat.so@
+ /usr/lib/core-linux-eglibc/libexpat.a
+ /usr/lib/core-linux-eglibc/libexpat.la*
+ /usr/lib/core-linux-eglibc/libexpat.so.1@
+ /usr/lib/core-linux-eglibc/libexpat.so.1.6.0*
+ /usr/include/
+ /usr/include/expat_external.h
+ /usr/include/expat.h
+
+We have the `libexpat.so.1.6.0` shared library and two symbolic links to it:
+`libexpat.so.1` and `libexpat.so`. We have the `libexpat.a` static library and
+associated `libexpat.la` library metadata file generated by GNU libtool. We
+have a pkg-config file and two header files. We have an executable utility and
+an associated manual page.
+
+We should therefore split these files into four binary packages: one for the
+shared library, one for the library development files, one for the utility, and
+one for the utility's documentation.
+
+To find out what we should call the library package, we can use **objdump**(1)
+to get the *SONAME* of the library:
+
+ $ objdump -p tmp/dest/usr/lib/core-linux-eglibc/libexpat.so.1.6.0 | grep SONAME
+ SONAME libexpat.so.1
+
+We should name our library package after the SONAME of the shared library,
+without `.so`. The binary package shall be named **`libexpat.1`**.
+
+The versionless `libexpat.so` link is only needed by **ld**(1) when linking a
+just-compiled object with the `-lexpat` linker flag. So this can be provided by
+our library development package. Also provided by that package will be the
+header files, the pkg-config file, and the static library. The development
+package can be called **`libexpat.1-dev`**.
+
+The `xmlwf` utility can be provided by a package called simply **`xmlwf`**.
+
+The `xmlwf.1` manual page can be provided by a package called **`xmlwf-doc`**.
+
+
+Binary Packages
+===============
+
+Binary Package Metadata
+-----------------------
+
+Each binary package to be built needs to have [a directory for its
+metadata][spf-binpkg.pkg]. So let's create directories for our packages.
+
+ $ mkdir libexpat.1.pkg libexpat.1-dev.pkg xmlwf.pkg xmlwf-doc.pkg
+
+SPF 2.0 requires a `control` file for each binary package. The format of this
+file is the same as that of the source package `control` file. The required
+[binary package fields][spf-fields-bin] are `Architecture`, `Platform`, and
+`Description`.
+
+None of these binary packages are platform-specific, so they will all have a
+`Platform: all` field. All of the binary packages except `xmlwf-doc` are
+architecture-specific; that is, they provide files whose contents depend on the
+host architecture (files like executable and linkable objects). So `xmlwf-doc`
+will have an `Architecture: all` field while the others will have `Architecture:
+any` fields.
+
+Let's start with the `libexpat.1.pkg/control` file:
+
+ Architecture: any
+ Platform: all
+ Description: XML parser library
+ Expat is an XML parser library written in C. It is a stream-oriented parser in
+ which an application registers handlers for things the parser might find in the
+ XML document (like start tags).
+
+That's fairly simple.
+
+Now let's write a `control` file for `libexpat.1-dev`. Because it provides
+development files for `libexpat.so.1`, `libexpat.1-dev` should depend on the
+`libexpat.1` package. This should be a versioned dependency, because the
+`libexpat.so` symbolic link points to a specific version of `libexpat.so`.
+
+ Architecture: any
+ Platform: all
+ Depends: libexpat.1 (= 2.1.0-1)
+ Description: XML parser library - development files
+ Expat is an XML parser library written in C. It is a stream-oriented parser in
+ which an application registers handlers for things the parser might find in the
+ XML document (like start tags).
+ .
+ This package provides development files for Expat.
+
+Next is `xmlwf`, which should also depend on `libexpat.1` since the `xmlwf`
+utility is dynamically linked against the `libexpat.so.1` library.
+
+ Architecture: any
+ Platform: all
+ Depends: libexpat.1
+ Description: XML parser library - example application
+ This package provides an example application of Expat that determines if an XML
+ document is well-formed.
+
+Finally, we can write metadata for `xmlwf-doc`, which should depend on `xmlwf`
+since it documents the `xmlwf` utility.
+
+ Architecture: all
+ Platform: all
+ Depends: xmlwf
+ Description: XML parser library - example application documentation files
+ This package provides the manual page for xmlwf, an example application of
+ Expat that determines if an XML document is well-formed.
+
+Binary Package Data Files
+-------------------------
+
+The **oh-installfiles**(1) utility of opkhelper, which we'll be using to install
+files into *binary package data directories*, requires a `files` file for each
+binary package that is to provide data files.
+
+Recall how we decided to split files between packages. We will now write
+pathname patterns to do this.
+
+Again, let's start with `libexpat.1`. We can write the following pattern in
+`libexpat.1.pkg/files`:
+
+ /usr/lib/*/libexpat.so.*
+
+This will match `/usr/lib/core-linux-eglibc/libexpat.so.1` and
+`/usr/lib/core-linux-eglibc/libexpat.so.1.6.0`; these two files will be provided
+by `libexpat.1`.
+
+The patterns for `libexpat.1-dev` are a little more complicated:
+
+ /usr/include
+ /usr/lib/*/libexpat.so
+ /usr/lib/*/libexpat.a
+ /usr/lib/*/pkgconfig
+
+The first pattern simply matches the directory containing header files. The
+second matches the versionless symbolic link; remember this is used by **ld**(1)
+to link a just-compiled object against `libexpat.so.1.6.0`. The third matches
+the static library, and the fourth matches the directory containing the
+`expat.pc` pkg-config file.
+
+`xmlwf.pkg/files` need only contain a pattern to match the directory containing
+the `xmlwf` utility.
+
+ /usr/bin
+
+`xmlwf-doc.pkg/files` is similarly simple:
+
+ /usr/share/man/man1
+
+With these pathname patterns done, we can add **oh-installfiles**(1) to our
+`build` makefile:
+
+ #!/usr/bin/make -f
+
+ nop:
+ @:
+
+ build:
+ oh-autoconfigure
+ oh-autobuild
+ touch $@
+
+ install: build
+ oh-autoinstall
+ oh-installfiles
+
+Now run **opkbuild**(1) again:
+
+ $ opkbuild -b -c -T install
+
+You can verify that all files were installed where they should be:
+
+ $ find tmp/*.data -exec ls -Fd '{}' ';'
+ tmp/libexpat.1.data/
+ tmp/libexpat.1.data/usr/
+ tmp/libexpat.1.data/usr/lib/
+ tmp/libexpat.1.data/usr/lib/core-linux-eglibc/
+ tmp/libexpat.1.data/usr/lib/core-linux-eglibc/libexpat.so.1@
+ tmp/libexpat.1.data/usr/lib/core-linux-eglibc/libexpat.so.1.6.0*
+ tmp/libexpat.1-dev.data/
+ tmp/libexpat.1-dev.data/usr/
+ tmp/libexpat.1-dev.data/usr/lib/
+ tmp/libexpat.1-dev.data/usr/lib/core-linux-eglibc/
+ tmp/libexpat.1-dev.data/usr/lib/core-linux-eglibc/pkgconfig/
+ tmp/libexpat.1-dev.data/usr/lib/core-linux-eglibc/pkgconfig/expat.pc
+ tmp/libexpat.1-dev.data/usr/lib/core-linux-eglibc/libexpat.so@
+ tmp/libexpat.1-dev.data/usr/lib/core-linux-eglibc/libexpat.a
+ tmp/libexpat.1-dev.data/usr/include/
+ tmp/libexpat.1-dev.data/usr/include/expat_external.h
+ tmp/libexpat.1-dev.data/usr/include/expat.h
+ tmp/xmlwf.data/
+ tmp/xmlwf.data/usr/
+ tmp/xmlwf.data/usr/bin/
+ tmp/xmlwf.data/usr/bin/xmlwf*
+ tmp/xmlwf-doc.data/
+ tmp/xmlwf-doc.data/usr/
+ tmp/xmlwf-doc.data/usr/share/
+ tmp/xmlwf-doc.data/usr/share/man/
+ tmp/xmlwf-doc.data/usr/share/man/man1/
+ tmp/xmlwf-doc.data/usr/share/man/man1/xmlwf.1
+
+Cleaning Up Installed Files
+---------------------------
+
+There are few things we can do to improve our `build` makefile's `install`
+target.
+
+You may have noticed **oh-installfiles**(1) warn that something hasn't been
+installed:
+
+> oh-installfiles: Warning: Some files have not been installed into packages
+
+With **find**(1), we can see that this is the `libexpat.la` file that GNU
+libtool generated.
+
+ $ find tmp/dest -type f -exec ls -Fd '{}' ';' | sed 's|^tmp/dest||'
+ /usr/lib/core-linux-eglibc/libexpat.la*
+
+We don't need this, and we can simply delete it in the `install` target.
+
+Next, note that some file permissions aren't entirely correct. For example,
+`libexpat.so.1.6.0` is executable, but almost all libraries need not be.
+
+So we can call **oh-fixperms**(1) in our `install` target to automatically set
+correct permissions for us.
+
+Finally, note that the executable and linkable objects are not stripped: they
+contain all of their symbols, including those only needed for debugging.
+
+ $ file tmp/libexpat.1.data/usr/lib/core-linux-eglibc/libexpat.so.1.6.0
+ tmp/libexpat.1.data/usr/lib/core-linux-eglibc/libexpat.so.1.6.0: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, BuildID[sha1]=0x2d88e36feeb8245bfa2f63f2f0e9a9f8232f6d2c, not stripped
+ $ file tmp/xmlwf.data/usr/bin/xmlwf
+ tmp/xmlwf.data/usr/bin/xmlwf: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.26, BuildID[sha1]=0xdb5f686930b13b8a5e7519efb446a2da14de9856, not stripped
+
+We can call **oh-strip**(1) in our `install` target to automatically strip
+objects for us.
+
+So our `build` makefile should now look like this:
+
+ #!/usr/bin/make -f
+
+ nop:
+ @:
+
+ build:
+ oh-autoconfigure
+ oh-autobuild
+ touch $@
+
+ install: build
+ oh-autoinstall
+ rm -f 'dest/usr/lib/$(OPK_HOST_ARCH)/libexpat.la'
+ oh-fixperms
+ oh-strip
+ oh-installfiles
+
+[spf-binpkg.pkg]: http://specs.proteanos.com/spf-2.0/overview.html#files-binpkg.pkg
+[spf-fields-bin]: http://specs.proteanos.com/spf-2.0/fields.html#fields-src
+
+
+Documentation and Finishing Touches
+===================================
+
+Source Package Documentation
+----------------------------
+
+SPF 2.0 [specifies][spf-docs] that one of the binary packages built from a
+source package provides documentation files about the source package and is
+depended upon by all of the other binary packages from the source package.
+
+So we should pick one common binary package that should be a dependency of all
+of our other binary packages. `libexpat.1` is a good candidate for this, since
+it is already a direct dependency of `libexpat.1-dev` and `xmlwf` and an
+indirect dependency of `xmlwf-doc`.
+
+Per SPF 2.0, we can mark `libexpat.1` as providing source package documentation
+by making a `docs` file in its metadata directory.
+
+ $ touch libexpat.1.pkg/docs
+
+We should make all of our other binary packages directly depend on `libexpat.1`
+version `2.1.0-1`. For example, `xmlwf-doc.pkg/control` should now look like
+this:
+
+ Architecture: all
+ Platform: all
+ Depends: libexpat.1 (= 2.1.0-1), xmlwf
+ Description: XML parser library - example application documentation files
+ This package provides the manual page for xmlwf, an example application of
+ Expat that determines if an XML document is well-formed.
+
+Substitution Variables
+----------------------
+
+We've hardcoded the `libexpat.1` binary package version in many of our control
+files. What will we do when we make a new version of our source package? We'll
+have to change all of these values in all of these places.
+
+[*Substitution variables*][spf-substvars] (*substvars* for short) make this
+unnecessary. We can just use the `Binary-Version` substitution variable in our
+control files to refer to the version of our binary packages. For example, our
+`xmlwf-doc.pkg/control` file should now look like this:
+
+ Architecture: all
+ Platform: all
+ Depends: libexpat.1 (= ${Binary-Version}), xmlwf
+ Description: XML parser library - example application documentation files
+ This package provides the manual page for xmlwf, an example application of
+ Expat that determines if an XML document is well-formed.
+
+But that's not all! We can define our own variables as well.
+
+Note that the descriptions of our `libexpat.1` and `libexpat.1-dev` packages
+have a common paragraph. We can put that in a file called `substvars`:
+
+ Common-Description:
+ Expat is an XML parser library written in C. It is a stream-oriented parser in
+ which an application registers handlers for things the parser might find in the
+ XML document (like start tags).
+
+As noted by the SPF 2.0 specification, the leading newline character in the
+value is fine:
+
+> Values may be comprised of multiple lines, and empty lines at the beginning
+> and end of each substitution variable value shall be removed.
+
+We can now use this variable in our `control` files. Here's
+`libexpat.1.pkg/control`:
+
+ Architecture: any
+ Platform: all
+ Description: XML parser library
+ ${Common-Description}
+
+And here's `libexpat.1-dev.pkg/control`:
+
+ Architecture: any
+ Platform: all
+ Depends: libexpat.1 (= ${Binary-Version})
+ Description: XML parser library - development files
+ ${Common-Description}
+ .
+ This package provides development files for Expat.
+
+Copyright and License Information
+---------------------------------
+
+We're almost done; we just have one more important thing to do. We need to
+document the copyright information for the upstream software and our own
+packaging work.
+
+This is done in the `copyright` file. There is currently no standard format for
+this file.
+
+We need to collect the copyright and license information from the upstream
+source code (usually in comments at the tops of source files).
+
+There are some resources available to assist us with this. First, we can look
+at the work already done by package maintainers in the Debian Project. Find the
+[copyright file][deb-expat-copyright] for Debian's `expat` source package.
+
+We see the following copyright information:
+
+ Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd
+ and Clark Cooper
+ Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006 Expat maintainers.
+
+We also see that Expat can be dealt in under the terms of, unsurprisingly, the
+Expat (a.k.a. "MIT") license.
+
+Another resource we can use is the [**licensecheck**(1) tool][licensecheck],
+maintained in Debian's `devscripts` package and originally based on a script
+from the KDE SDK. Recursively run **licensecheck**(1) to report copyright and
+license information.
+
+ $ licensecheck -r --copyright tmp/src/
+
+We see that some source files have publication dates in their copyright notices
+that are newer than those that Debian's copyright file lists:
+
+ tmp/src/amiga/expat_lib.c: MIT/X11 (BSD like)
+ [Copyright: 2001-2009 Expat maintainers / HOLDERS BE LIABLE FOR ANY]
+
+So collect some representative copyright notices – e.g. from
+`tmp/src/lib/xmlparse.c`, `tmp/src/examples/outline.c`,
+`tmp/src/vms/expat_config.h`, and `tmp/src/amiga/expat_lib.c` – and add them to
+the `copyright` file.
+
+Then describe the license under which the software may be used. `Expat` is a
+"common license" included under `/usr/share/common-licenses/` in this
+distribution, so you can refer to it there.
+
+You should also document the location from which the source was obtained.
+
+Finally, add your own copyright notice and license information. You should
+allow your work to be used under the terms of a license that is equivalent to or
+compatible with the terms of the upstream software's copyright license.
+
+Your resulting `copyright` file might look something like this:
+
+ Upstream Source
+ ===============
+
+ Location: <http://sourceforge.net/projects/expat/files/expat/>
+
+ Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd
+ Copyright 1999, Clark Cooper
+ Copyright 2000, Clark Cooper
+ Copyright (c) 2001-2009 Expat maintainers.
+
+ These files may be reproduced, distributed, modified, and otherwise dealt in
+ under the terms of the Expat License.
+
+ On this system, a copy of the Expat License may be found at
+ <file:///usr/share/common-licenses/Expat>.
+
+
+ Distribution Packaging
+ ======================
+
+ Copyright (C) 2012 J. Random Hacker
+
+ These files may be reproduced, distributed, modified, and otherwise dealt in
+ under the terms of the Expat License.
+
+ On this system, a copy of the Expat License may be found at
+ <file:///usr/share/common-licenses/Expat>.
+
+Building Everything
+-------------------
+
+Now we can build all of our source and binary packages and verify that
+everything is correct.
+
+**opkbuild**(1) maintains a cache file in the work area; because we've modified
+the metadata in our packaging since the first time we ran **opkbuild**(1), this
+cache file is out-of-date. Also, we should make sure that the entire build
+process still works. So let's clean up the work area before going any further.
+
+ $ rm -Rf tmp/
+
+Now let's run **opkbuild**(1) again, this time completely building all of our
+source and binary packages and cleaning up automatically when we're done.
+
+ $ opkbuild
+
+After that finishes, you should see the built packages in the parent directory.
+
+ $ ls -1 ../*.opk
+ ../libexpat.1_2.1.0-2_core-linux-eglibc_all.opk
+ ../libexpat.1-dev_2.1.0-2_core-linux-eglibc_all.opk
+ ../src-expat_2.1.0-2_src_all.opk
+ ../xmlwf_2.1.0-2_core-linux-eglibc_all.opk
+ ../xmlwf-doc_2.1.0-2_all_all.opk
+
+`src-expat` is a *source binary package* – a binary package installable with the
+package manager that provides the files in our source package. This binary
+package is a convenient way to distribute our source package to others.
+
+You can use the **tar**(1) command to verify that the control information and
+data files in packages look correct.
+
+ $ tar -xzO control.tar.gz \
+ > <../libexpat.1_2.1.0-2_core-linux-eglibc_all.opk | tar -xzO ./control
+ Package: libexpat.1
+ Source: expat
+ Version: 2.1.0-2
+ Architecture: core-linux-eglibc
+ Platform: all
+ Maintainer: "J. Random Hacker" <jrandom@example.com>
+ Installed-Size: 164
+ Description: XML parser library
+ Expat is an XML parser library written in C. It is a stream-oriented parser in
+ which an application registers handlers for things the parser might find in the
+ XML document (like start tags).
+ Homepage: http://expat.sourceforge.net/
+ $ tar -xzO data.tar.gz \
+ > <../libexpat.1_2.1.0-2_core-linux-eglibc_all.opk | tar -tz
+ ./
+ ./usr/
+ ./usr/share/
+ ./usr/share/doc/
+ ./usr/share/doc/libexpat.1/
+ ./usr/share/doc/libexpat.1/changelog.dist
+ ./usr/share/doc/libexpat.1/copyright
+ ./usr/lib/
+ ./usr/lib/core-linux-eglibc/
+ ./usr/lib/core-linux-eglibc/libexpat.so.1
+ ./usr/lib/core-linux-eglibc/libexpat.so.1.6.0
+
+Congratulations! You've made a source package that successfully builds four
+binary packages!
+
+[spf-docs]: http://specs.proteanos.com/spf-2.0/metadata.html#docs
+[spf-substvars]: http://specs.proteanos.com/spf-2.0/substvars.html
+[deb-expat-copyright]: http://packages.debian.org/changelogs/pool/main/e/expat/current/copyright
+[licensecheck]: http://anonscm.debian.org/gitweb/?p=devscripts/devscripts.git;a=blob;f=scripts/licensecheck.pl;hb=HEAD