[Previous] [Contents] [Index] [Next]

Appendix: Creating Packages

This appendix includes:

If you want to create packages that other users can install, the easiest way is to use the packager utility. It leads you through the process, and it prompts you for the required information. If you have a QNX Package Manifest (qpm) file, you can speed up the process by having packager use it for the default answers.

Packages keep all aspects of a product in one manageable file. A package is similar to a .tgz file -- it's a compressed version of all of the files that make up your product.

Packages, however, have additional elements beyond the standard "tarball" you may have seen before. Packages also include a manifest, and any support files used within the package, such as licenses, scripts, or HTML web pages. Since all of this information is packaged together, the QNX software installer can extract the required information to install your product into the package filesystem (which, by default, manages all software on your system).

This appendix describes the packager utility and how you can use it to combine your own product into a set of packages that you can either distribute or make available on a repository (a set of packages at a particular URL location).

QNX package manifests (QPM)

The QNX package manifest (QPM) file describes all aspects of a package, including:

You can use any standard ASCII text editor to edit the QPM file, which follows XML formatting guidelines. However, we recommend that you not edit the file by hand. Instead, you should make any changes to the package as part of a repackaging procedure, using packager. This not only ensures that the data is entered correctly, it also updates other information automatically, such as the date that the package was created, the release number, and the size of your product. The packager also gathers and compresses your files into the required structure.

The packager utility

The packager utility generates packages with all the necessary tags to comply with both current and future versions of the QNX software installer. You can also use packager to repackage existing packages to reflect updates in the program or to create patches from a previous package to a new one.

There are a lot of tags that make up a QPM file, so you should expect a correspondingly large number of questions in order to make a package that is accurate and detailed. The packager was designed as a command-line utility so that after you've answered these questions once, it's easy to pass your previous package as a command-line argument and bypass the questions next time.

If you look at the documentation for packager in the Neutrino Utilities Reference, you'll see that there are many options that you can specify. Don't let this daunt you -- you can create a package-generation (QPG) file that lets you automate the packaging process, and then you'll have to type only packager to build a brand-new package at any time. For more information, see "Working with a package-generation (QPG) file," later in this appendix.

When packager asks you a question, it provides a default value in parentheses, like this: (default). To use the default value, press Enter without entering any text. Press Ctrl-B to go to the previous question if you make a mistake.

The packager utility gives you detailed comments about each question (by default). Once you're used to the questions, you can pass the -v1 (advanced mode) or -v2 (expert mode) option to reduce the amount of information shown for each question.

The default packaging method that packager uses expects that you pass it a directory as the only argument. This directory holds all of the files that you would like to have packaged, laid out in a directory structure that reflects the root (/) filesystem, when the files are installed. Public software should all be installed under the /opt directory. For example, if you type:

packager basedir/

then packager takes all files under basedir and puts them into your package by creating a QPM file. This file lists all answers to the questions, along with a list of the files under the basedir directory.

The packager also creates a QNX package file (QPK) which is a tarred/gzipped archive of the manifest file (renamed MANIFEST), and each of the files in the basedir directory. By default, packager also creates a QNX repository file (QPR) which is itself a tarred/gzipped archive of the QPM and QPK files. You can view the contents of a QPK or a QPR file by typing tar -ztf filename.qpk.

When packager is sorting your files, it automatically detects any executable files made to execute on a particular processor (host) and creates a separate package to put these files into; packager also automatically makes links between these processor-specific and processor-independent packages. So, when packager is working, you may see two QPM files and two QPK files created. The QPR file is an archive of all four files. In fact, if you have files to be hosted on other processors, a separate QPR file is created for each processor.

In addition, if you have executable files that generate files targeting different processors or header (.h) files, packager starts to create development packages with a -dev- qualifier in the file name. There's no limit to how many packages packager may create as it works, although you can expect to see two for a standard package, and perhaps six for an advanced one.

Preparing to package

Before you run packager, put your files into a directory structure that reflects where they should appear when someone installs your package. You can do this in a number of different ways:

Running packager

You'll find that packager asks many questions. Here are some hints for answering them:

Here are some of the more important things that packager might ask about your package:

Product identifier
The name used by other packages to reference your package. It should be a short, simple identifier (no more than 13 characters), and be made up only of alphanumeric characters, dashes, and underscores. Ideally it should be a single lowercase word that's a short form of your product name.
Vendor identifier
Your company's name or your name. This helps ensure that your packages don't conflict with anyone else's (that may have identical product identifiers). Together, the vendor identifier and product identifier describe your product uniquely within the QNX community.
Release version
The version number of your product (e.g. 1.0, 2.3.4, 14.2A). If you're porting software from another source, you should use the software's original version number and simply change the release-build number each time you remake the software. If you do this, the version number accurately reflects the source-program's version.
Release build
An integer that indicates the build number of your package. You should increment this number by one each time that you change your software, unless you change the version number. You should reset the release-build number to 1 whenever the version changes.
Package release
An integer that indicates the release number of your package. You should increment this number by one each time you repackage your software, even if you haven't changed the software. You should reset this number to 1 whenever the version or build number changes.
Content topic
The topic you select for your package from the list supported by the QNX software installer. The packager shows all available topics and lets you select increasingly specific topics until you've fully described the location where you want your package to appear in your repository. The packager lets you search by keyword to quickly find an appropriate topic. The more specific you are in choosing the topic, the more organized your repository will be later, especially if the repository includes many packages.
Product name
The product's name is obviously very important for telling the user exactly what they're about to download/install. This is the name that appears in the QNX software installer in the list of packages in the repository, and should be a descriptive, capitalized name such as Packager or QNX Software Installer. The QNX software installer automatically tacks for x86, or similar qualifiers on the end when the package is displayed, so you don't have to enter processor or version references in this field.
Product description long
This field defines the complete description that appears in the QNX software installer when a user clicks on your package in the list of available packages. This field should consist of one or two paragraphs describing your product and its main features.
License URL
To have a license show up when your software is installed, you can specify the URL for the license file as your response to this question. By entering a file name that's on your local hard drive, you include a copy of the license file in your package (QPR) without having to put the file into your base directory structure. When you enter a local file in response to this question, the file is copied into the package.repdata directory that corresponds to your package. The packager displays a message stating that the file has been copied into the package. After you answer this question, you should confirm that this message is shown, or users might not be able to install your package.

After packager has asked you the basic questions, it sorts your software into the packages needed to properly install your product. Once this sorting is complete, packager asks you another set of questions.

Different questions apply to different packages. So for each package, packager first displays the name of the package, and then asks various questions, which can be divided into these main sections: scripts, dependencies, and the QNX Photon launch menu.

Scripts

You can execute scripts at the following times during the life of a package:

As well as choosing when the script is to be executed, you may decide to execute either your own script, or to simply run a program that's available on the filesystem.


Note: You can't execute a package's files before you activate the package or after you deactivate it.

Dependencies

Your package might need another package in order to operate correctly. Such requirements are specified by entering dependencies.


Note: The packager automatically inserts tags into your package that describe any shared-object libraries that your package contains or needs (packager runs objdump on all executable files in your package to determine any libraries that they need).

The QNX software installer automatically turns any required shared objects into dependencies that must be satisfied in order for your package to be installed. So, you don't need to add dependencies on packages that provide shared objects that your product inherently requires (e.g. if you're packaging a QNX Photon microGUI application, an automatic dependency on libph.so.2 is placed in your package).


Also, packager automatically puts in dependencies between any development packages that it generates, so you don't need to add dependencies between these packages either.

For any other situation where your package requires another package's presence, you can manually specify a dependency when packager prompts you. To enter a dependency, simply enter the name of any file on your local system that's required for proper operation of your package. The packager automatically determines the package from which the file originated and adds the dependency on that package into your new package.

Photon launch menu

You may specify any number of items to appear in QNX Photon's launch menu when this package is active. For each, answer the questions as follows:

Launch menu position
The name to appear on the launch menu. This name shouldn't be longer than 25 characters.
Topic
The hierarchy under which the entry is to appear. You can enter any values here, but they must all be under the Applications/ heading. You should stick to the standard ones shown in the launch menu (i.e. Applications/Editors, Applications/Utilities, Applications/Internet, Applications/MultiMedia, Applications/Development, or Applications/Games).
Execution command
The command to execute when the operator clicks on the menu item. This must be a fully qualified command (e.g. /usr/photon/bin/ped -r readme.txt).

Warnings and error messages

As packager works to create your packages, it displays many messages, starting with a welcome message indicating the process that is about to be undertaken. If packager detects any problems with the command-line options that you've entered, it displays an error message, followed by its standard usage message. If you see this usage message, check above it for possible indications of what went wrong. If no error is shown, confirm that the options that you entered are valid. Here are some of the warnings and errors you may encounter:

Warning: /usr/local should not be packaged using this utility.
The /usr/local directory is considered to be a special directory that can contain files from a number of different software packages. The packager utility is intended for a single product that should install its files into /opt/bin, /usr/share, or similar directories. You should copy the required files into a different directory before packaging commences.
Warning: There are files at the root, where only directories should reside.
All of your files should be installed into the correct directory. The packager detects if you have files destined to be installed at the root directory (/), where only subdirectories should ever appear (with the exception of system files). You should relocate your files to appear within the correct subdirectories.
Warning: Uncommon directory paths have been detected.
We recommend that you use a set of standard directories. Your files should all appear within this directory structure. If this message appears, you should relocate your files into one of the following standard root directories: /boot, /dev, /etc, /opt, /usr, or /var.
Error: This is a required field.
You must fully answer some of questions that packager asks; you may not simply accept the default value (or no value) for the question asked. The packager asks the question again until you answer it properly.
Error: This value cannot exceed n characters.
There is a maximum length to this field that must not be exceeded.
Error: QNX software can only be released by QNX Software Systems Ltd.
If you try to answer questions as if you were packaging QNX software, this message may appear. Answer with your own company or personal information.

Testing your package

Once you've created your package, try to install it using the QNX software installer, by typing:

qnxinstall -u mypackage.qpr

or:

cl-installer -o mypackage.qpr

The QNX software installer shows your software as a new package that's ready to be installed. When you install it, no errors or warnings should appear. You can then verify on the command line that your files are actually installed in the locations you've specified.

If your package doesn't show up in the QNX software installer, try adding a -v (verbose) option to your command line. The installer displays messages for any errors that it detects in the package. If your package is shown as being installed already, you may have chosen the same product identifier or vendor identifier as another package that's already installed.

If there appear to be missing files, or something simply doesn't seem to be correctly installed, you can check the manifest for the packages you've installed. As long as you're using the default user repository to install your package, the files are located in /pkgs/repository. Under that directory, find your vendor directory, then the package identifier directory, and finally the version directory. For example, if packager had its own package, it would be found at /pkgs/repository/qnx/packager/core-1.1/.

Inside this directory, you'll find a file called manifest. This is a copy of the QPM file for this package and includes all processor-independent information about the package. If you have processor-specific components to your package, look for a subdirectory with the same name as the processor (e.g. x86), which contains another manifest for the processor-specific portion of your package.


Caution: If you choose to edit the manifest file, make sure that you follow the XML formatting rules. If you change some values, you might make your package unusable, to the point where the QNX software installer won't understand the package well enough even to remove it! This information is for reference purposes only, and you should remember that using the packager utility is the only correct way to make your packages.

Working with a package-generation (QPG) file

Learning to automate the packaging process means that future changes to your software are easily reflected in a new package without much effort. Here are the steps you'll follow:

  1. Generate your package.
  2. Tell packager to generate a QPG (QNX Package Generation) file from your package
  3. Edit the QPG to point to your source files on disk.
  4. Pass the QPG file to packager to regenerate your package.
  5. Test the resulting package.

You can use the QPG file to provide the command-line options and answers to packager's questions automatically, without your intervention. It's also an XML-style document that you can edit using any standard ASCII text editor (but we don't recommend this). You can generate an initial QPG file by typing:

packager -m mypackage.qpr -x basedir

This command generates a file called package.qpg that contains the manifest values in your package, and a reference to each of the files inside your package. The basedir that you specify should be the directory that you created in your initial packaging session, where your files reside.

If you do a use packager command, you may notice that packager accepts either a basedir or a qpg_file as its final argument. If you don't specify a basedir on the command line when you start packager, you can specify a QPG file name for packager to use. If you don't specify one, packager looks for a package.qpg file by default. This lets you simply type packager on the command line, and packager rebuilds your package according to the options in the local package.qpg file.

A QPG file has these main sections:

For more information about the options in a QPG file, see "QPG structure," below.

Here's a sample QPG file that shows all the elements that might appear in your final generation file:

<QPG:Generation>
  <QPG:Options>
    <QPG:User unattended="yes" verbosity="1" listfiles="yes"/>
    <QPG:Release number="+"/>
    <QPG:Defaults type="qnx_package" file="my_package-1.0-x86-qnx.qpr"/>
    <QPG:FileSorting strip="yes"/>
    <QPG:Package targets="combine" union="terminate"/>
    <QPG:Repository generate="yes"/>
  </QPG:Options>

  <QPG:Responsible>
    <QPG:EmailAddress>joe_blow@home.com</QPG:EmailAddress>
    <QPG:Company>My Company Inc.</QPG:Company>
    <QPG:Department>Research and Development</QPG:Department>
  </QPG:Responsible>

  <QPG:Merge file="common/exclusions.qpg"/>
        
  <QPG:Values>
    <QPG:Files>
      <QPG:Add file="CVS" handling="exclude"/>
      <QPG:Add file="src/gcc_ntox86/pkg-installer" permissions="u+s" install="/opt/photon/bin/"/>
      <QPG:Add type="tree" file="config/" install="/"/>
      <QPG:Add file="/usr/lib/libsocks.so" install="/usr/test/libsocks.so.1" proc="arm"/>
      <QPG:Add type="file" file="/usr/lib/libsocks.a" install="/usr/test/" target="arm"/>
      <QPG:Add file="/usr/test/libsocks.so" install="/usr/test/" filetype="symlink" linkto="libsocks.so.1"/>
    </QPG:Files>
        
    <QPG:PackageFilter>
      <QPM:PackageManifest>
        <QPM:PackageDescription>
          <QPM:PackageType>Application</QPM:PackageType>
          <QPM:PackageReleaseUrgency>Low</QPM:PackageReleaseUrgency>
          <QPM:PackageReleaseNotes/>
          <QPM:PackageRepository/>
          <QPM:PackageReleaseNumber/>
        </QPM:PackageDescription>

        <QPM:ProductDescription>
          <QPM:ProductName>Tast</QPM:ProductName>
          <QPM:ProductIdentifier>tast</QPM:ProductIdentifier>
          <QPM:ProductEmail>support@home.com</QPM:ProductEmail>
          <QPM:VendorName>My Company Inc.</QPM:VendorName>
          <QPM:VendorInstallName>myco</QPM:VendorInstallName>
          <QPM:VendorURL>www.home.com</QPM:VendorURL>
          <QPM:VendorEmbedURL/>
          <QPM:VendorEmail>support@home.com</QPM:VendorEmail>
          <QPM:AuthorName>Joe Blow</QPM:AuthorName>
          <QPM:AuthorURL/>
          <QPM:AuthorEmbedURL/>
          <QPM:AuthorEmail/>
          <QPM:ProductIconSmall/>
          <QPM:ProductIconLarge/>
          <QPM:ProductHomeURL/>
          <QPM:ProductDescriptionEmbedURL/>
          <QPM:ProductDescriptionURL/>
        </QPM:ProductDescription>
        
        <QPM:ReleaseDescription>
          <QPM:ReleaseDate>2001/03/01</QPM:ReleaseDate>
          <QPM:ReleaseVersion>1.0</QPM:ReleaseVersion>
          <QPM:ReleaseUrgency>Medium</QPM:ReleaseUrgency>
          <QPM:ReleaseStability>Stable</QPM:ReleaseStability>
          <QPM:ReleaseNoteMinor>Initial public release</QPM:ReleaseNoteMinor>
          <QPM:ReleaseNoteMajor>This initial public release of Tast coincides
            with the deadlines set forth in the company prospectus.</QPM:ReleaseNoteMajor>
          <QPM:CountryExclude/>
        </QPM:ReleaseDescription>
        
        <QPM:ContentDescription>
          <QPM:ContentTopic>Software Development/Build Tools/Packaging</QPM:ContentTopic>
          <QPM:ContentKeyword>tast,sample</QPM:ContentKeyword>
          <QPM:DisplayEnvironment>Console</QPM:DisplayEnvironment>
          <QPM:TargetAudience>Developer</QPM:TargetAudience>
        </QPM:ContentDescription>

        <QPM:ProductInstallationDependencies>
          <QPM:ProductRequirements>No extra requirements.</QPM:ProductRequirements>
        </QPM:ProductInstallationDependencies>

      </QPM:PackageManifest>
    </QPG:PackageFilter>

    <QPG:PackageFilter type="core" component="none">
      <QPM:FileManifest>
        <QPM:Launch name="QNX Software Systems" xmlmultiple="true">
          <QPM:String name="Topic" value="Applications/Development"/>
          <QPM:String name="Command" value="/usr/photon/bin/voyager -u http://www.qnx.com"/>
        </QPM:Launch>
      </QPM:FileManifest>
    </QPG:PackageFilter>

  </QPG:Values>
</QPG:Generation>

Note: Edit the QPG file carefully since it must follow the XML format, where each opening tag has a corresponding closing tag, and spelling mistakes aren't tolerated.

The list of files, <QPG:Files>, is the most advanced (and flexible) part of the QPG file. Here, you can list the files to package from your hard disk (in any location), the location where they should appear once the package is installed, the types of files they are, any special handling for the files, and any files that should be excluded from your package. The packager utility automatically determines each of these values, if they aren't specified, as long as you provide the source file name (with the file attribute) and the install location (the install attribute).

The <QPG:PackageFilter> section is where you place manifest tags that you would like to appear in the final package manifest(s). The easiest way to fill in this section is to let packager create the QPG for you (-x option). However, when you're trying to add a special feature of some kind, e.g. launch-menu items, you can edit this section to include all the tags you need.

The packager determines some manifest tags each time that you run it. so specifying those values has no effect in the generated packages. An empty tag has the effect of suppressing the question for that tag when you run packager in attended mode.

Symbolic links

To create a symbolic link, add another <QPG:Add> line like this to your QPG file:

<QPG:Add file="sym_link_name" install="/opt/bin/"
         filetype="symlink" linkto="file/to/link/to"/>

When packager detects the filetype="symlink" attribute, it recognizes this as a request to put a symbolic link into one of your packages. It automatically searches the other files being packaged, looking for the file that the symbolic link points to. When packager finds the file, it places the symbolic link into the same package as the file.

For example, to add a file, libmine.so, from your hard drive, but install it as a different file, libmine.so.1, and then create a symbolic link from libmine.so to libmine.so.1, specify these tags:

<QPG:Add file="src/lib/libmine.so" install="/opt/lib/libmine.so.1"/>
<QPG:Add file="libmine.so" install="/opt/lib/" filetype="symlink"
         linkto="libmine.so.1"/>

Working with components

Components are optional parts of a master product. Parts of your software can be installed with or without other components. For example, think of the set of Photon packages, which consists of a core package, a drivers component, a games component, and other components. With a single session of packager, you can generate a product and all of its components.

You can make any file that you're packaging a part of a component, by adding component="component_name" to the <QPG:Add> line:

<QPG:Add file="bin/my_game" install="opt/bin/" component="games"/>

When packager finds such a line, it puts the file into a new package that has a <QPM:PackageModel> tag of games, with the same product identifier as your core package. This new package is independent of the other portions of your product, but its installation location will be alongside the rest of the product it's derived from. For example:

/pkgs/base/qnx/ph/core-2.0.2/
/pkgs/base/qnx/ph/games-2.0.2/
/pkgs/base/qnx/ph/drivers-2.0.2/

Note that packager uses components automatically when it detects that you're attempting to package development files. Let's say you're packaging some header (*.h) files. When packager detects these files, it automatically creates a component for your package called dev. This development package contains all of the files that are part of the software-development process. Only executable files and configuration files actually go into the core product itself.

Forcing files into certain packages

If you don't want to create a development (dev) package for your software, or if packager puts a file into a package that you didn't want it to, it's possible to force packager to handle files differently. To do this, make further specifications on the <QPG:Add> line to tell packager exactly how to handle the file. For more information, see the description of the <QPG:Add> in "QPG structure," later in this appendix.

Here are some examples that show common ways to redirect files:

Merging other QPG files

By adding a <QPG:Merge> entry into your QPG file, you can simplify a complicated product into a number of easy-to-manage QPG files. Note that packager reads the <QPG:Options> block only from the primary QPG file; packager ignores a merged QPG file's option block.

For example, your package.qpg file might show:

<QPG:Merge file="author.qpg"/>
<QPG:Merge file="drivers.qpg"/>
<QPG:Merge file="/home/common/license.qpg"/>

Here's a sample license.qpg you can use to add a license to your package:

<QPG:Generation>
 <QPG:Values>
  <QPG:PackageFilter>
   <QPM:PackageManifest>
    <QPM:ReleaseDescription>
     <QPM:ReleaseCopyright>Public Domain License</QPM:ReleaseCopyright>
     <QPM:ReleaseCopyrightURL>rep://LicenseUrl/license.txt</QPM:ReleaseCopyrightURL>
    </QPM:ReleaseDescription>

    <QPM:LicenseUrl>repdata://LicenseUrl/license.txt</QPM:LicenseUrl>
   </QPM:PackageManifest>
  </QPG:PackageFilter>
  
  <QPG:Files>
   <QPG:Add file="/location/of/your/license.txt"
      install="LicenseUrl/license.txt" handling="repdata"/>
  </QPG:Files>
 </QPG:Values>
</QPG:Generation>

If you want to use this file, add the <QPG:Merge> line to your main QPG file and be sure to remove the manifest tags that are referenced in the license.qpg file (i.e. <QPM:ReleaseCopyright>, <QPM:ReleaseCopyrightURL>, and <QPM:LicenseURL>) from your main QPG file.

When merging, you may want to apply a set of file attributes to an entire QPG file. For instance, you might change the destination component for the files referenced within the QPG. To do this, use a <QPG:MergeFilter> block with the desired attributes around any number of <QPG:Merge> commands:

<QPG:MergeFilter component="games">
    <QPG:Merge file="src/games/photon_games.qpg"/>
    <QPG:Merge file="src/games/xphoton_games.qpg"/>
</QPG:MergeFilter>

SLIB packages

The packager automatically detects any shared-object libraries (*.so files) that you're packaging and inserts a corresponding <QPM:ContainsLibrary> tag into the manifest of a package that contains such a library:

<QPM:ContainsLibrary>libmine.so.1</QPM:ContainsLibrary>

Similarly, if any files you're packaging require a shared object library in order to operate correctly (and you aren't packaging such a library alongside the files), then packager automatically adds a corresponding <QPM:RequiresLibrary> tag into the manifest of the package that contains such a requirement. This becomes an automatic dependency when the package is installed.

If the required library isn't available, the QNX software installer searches all installed software to try to find another package that contains the required library. If such a package isn't installed, the QNX software installer searches all known repositories for a package that contains the corresponding <QPM:ProvidesLibrary> tag. To avoid downloading a large package that happens to contain the library you require, and perhaps a lot of unnecessary files as well, the QNX software installer tries to find a small package that contains only a set of libraries. Such a package is called a SLIB package.

When you're packaging your files and a shared object library is detected, the library is copied into the package you're making, as well as into a SLIB package. This SLIB package has a similar name to your package; the only difference is that the component name has slib- added to it. The SLIB package is made available alongside your product (in the same repository), but it doesn't show up in the installer as a new package. It's there only for dependency resolution, in case someone installs a package that requires one of your libraries, but doesn't already have your product installed.

For example, if you're packaging a QNX Photon microGUI application, your application already requires phlib.so.1 internally, and packager puts these requirements into your package. The great advantage of SLIB packages is that you don't have a separate dependency that QNX Photon be installed, since this happens automatically when your package is installed.

Regenerating a package

Each time you generate a package, you must change its version number, its build number, or its release number. By doing so, you ensure that the QNX software installer will uninstall any previous versions of the program and will recognize your package as being a newer version than the one already installed.

You can change the version number for your software at any time, usually to indicate that its features have changed, or that a new architecture is in place. You can set the version number in the QPG file under the <QPM:ReleaseVersion> tag. You must use this format:

major[.minor[.sub]][letter]

For example: 1.0, 1.0A, 2.13.0, 2.13.1A, 7.15.433B

If you're keeping the same version, you can change the build number (an integer) to indicate that the software has been rebuilt, perhaps after you've fixed bugs or made minor changes. You can set the build number in your QPG using the <QPM:ReleaseBuild> tag, however, this fixes the build number and forces you to change the QPG each time you execute packager. A better method is to set an option in the <QPG:Generation> block. Add the <QPG:Build> tag and either set the build number to + (auto-increment), or to date (use today's date in the form, yyyymmddhh). You can also set the build number from the command line by using the -b option.

If you're keeping the same version and build number, you can change the release number to indicate that the software hasn't been modified and that you're simply repackaging the software. The packager automatically increases the release number (an integer) each time you run packager, although it resets the release number to 1 whenever the build number changes.

You can also set the release number in your QPG using the <QPM:PackageReleaseNumber> tag. However, this also fixes the release number and forces you to change the QPG each time that you run packager. You can disable auto-incrementation by setting the block. Add the tag and set the release number to - (don't auto-increment). You can also disable auto-incrementation from the command line, by using the -i option.

QPG structure

You can use QPG files to tell the packager utility how to generate packages, so that you don't need to have direct intervention when building packages; this permits automated packaging as needed. The main advantage is that files don't need to appear in a directory structure that matches the installation directory structure -- this is a significant advantage over the packager utility's default operation, and lets you keep your development setup without having to copy the files to another part of your filesystem.

The basic structure of sections in a QPG file is as follows:

<QPG:Generation>
   <QPG:Options>
   </QPG:Options>

   <QPG:Responsible>
   </QPG:Responsible>

   <QPG:Owner>
   </QPG:Owner>

   <QPG:MergeFilter>
   </QPG:MergeFilter>
   ...

   <QPG:Merge>
   </QPG:Merge>
   ...

   <QPG:Generate>
   </QPG:Generate>
   ...

   <QPG:Values>
      <QPG:PackageFilter>
      </QPG:PackageFilter>
      ...

      <QPG:Files>
         <QPG:Add>
         </QPG:Add>
         ...

         <QPG:File>
         </QPG:File>
         ...

      </QPG:Files>
   </QPG:Values>

</QPG:Generation>

Any QPG file can reference other QPG files (using the <QPG:Merge> specifier). Thus, your main QPG can reference a number of smaller (easier to manage) QPG files. Merging QPG files lets you add to the list of files to be packaged (see <QPG:Files>), and define the manifest settings that will be used for all generated packages (see <QPG:PackageFilter>).


Note: The <QPG:Options> section (command-line adjustments) isn't merged -- packager uses only the primary QPG file's <QPG:Options> section.

For example, you might have one QPG file that sets up a product's license settings and adds the license.txt file to the package.

Use a <QPG:Add> entry for each file that you want to include in the package. Wildcards are allowed, or you can add an entire directory or directory tree.

Note the following:

<QPG:Generation>

This is the top-level tag for a QPG file. This tag can include the following tags:

<QPG:Options>

The options that you put in this section specify the command-line options to be used when you run packager. Options that you actually specify on the command-line override any options entered in the QPG file (unless you specify the -y option). Options are used in the original (first) QPG file only; merged QPG files' options are ignored.

<QPG:User>
This tag controls how much help packager gives you. The attributes include:
<QPG:Defaults>
Where to find the default answers for packager's questions. The attributes include:
<QPG:Source>
Where to find the source files. The only attribute is:

If you don't specify this entry, and you don't specify the base directory on the command line, then packager doesn't do a directory scan; only files in QPGs are packaged.

<QPG:Release>
Specifications for the release number. The attributes include:
<QPG:Build>
Specification for the build number:
<QPG:FileSorting>
Options to use when sorting:
<QPG:Package>
Options for the package as a whole:
<QPG:Repository>
Options for the repository:
<QPG:FinalDir>
The attributes include:
<QPG:Cleanup>
Options for cleaning up:

<QPG:Responsible>

This section specifies the company/department/employee who is responsible for the files referenced in this QPG. You can have as many occurrences of the following tags as you need, and you can omit any that you don't need:

<QPG:Owner>

This tag supports this attribute:

<QPG:MergeFilter>

You can define any number of attributes, which will be applied to all <QPG:Add> and <QPG:PackageFilter> entries within any merged QPG files within this block. For example, <QPG:MergeFilter component="drivers"> sets all subsequently merged QPG files within this block to have component="drivers" if the component attribute isn't already set.

This section can also appear within another <QPG:MergeFilter> block, if necessary (i.e. nesting is valid).

If a <QPG:Add> or <QPG:PackageFilter> tag has an inherit="no" attribute, then no attributes are inherited from any of its ancestor <QPG:MergeFilter> tags.

<QPG:Merge>

<QPG:Merge> entries specify another QPG file to include as if it were part of this QPG file. You can use any number of these tags to build a package from any number of small QPG files/programs.

This tag supports this attribute:

<QPG:Generate>

Optionally, a QPG file can specify that another package must be built as a result of building the current package. Another instance of the packager utility is started, and you can specify whether or not the current instance should wait for the second instance to finish. This is useful when you're generating dependent packages.

The attributes include:

<QPG:Values>

This block defines all the manifest values and files that you want to include in the package. Use <QPG:PackageFilter> to direct certain values into particular manifests. Files can have the same direction.

<QPG:PackageFilter> (multiple entries)

When you use a <QPG:PackageFilter>, you can specify any or all of the following attributes, which must all match in order to be merged into a particular package's manifest:

The following sections correlate directly to the MANIFEST tags, and the tags used must match exactly.


Note: Entries that you specify in this section explicitly cause an attended session of packager not to ask the questions that correspond to those entries.

<QPG:Files>

Use this section to specify the files and/or directories to include in the package you're generating. To get files into a package, you can specify a base directory on packager's command line, specify a <QPG:Source> tag in the <QPG:Options> section, or add any number of the following tags.

You can also use this section to exclude particular files from being packaged, or have them inserted into the QPK or QPR only (without being in the manifest).

<QPG:Add> (multiple entries)

Use this tag to add files to the package. Use a type attribute to specify what you're adding, and a file attribute to specify the file/directory to add. The values that you enter here are applied to all files added (pattern-matched). However, if a .pinfo file is also present, its values override the values specified here.

For example, to add a license file to the repository directory, use the following:

<QPG:Add file="./license.txt" install="LicenseUrl/" handling="repdata"/>

The corresponding <LicenseUrl> tag could be:

rep://packager-1.1-qnx.repdata/LicenseUrl/license.txt

A <QPG:Add> tag can enclose any number of <QPG:Rule> tags. For more information about rules (an advanced feature), see the description of the <QPG:Rule> tag later in this appendix.

The attributes for <QPG:Add> include:

<QPG:File> (multiple entries)

The packager utility creates these entries dynamically. Don't add this section by hand; use <QPG:Add> tags instead -- they allow pattern-matching (see above).

<QPG:Rule>

When you use a <QPG:Add> tag to add a file, the tag can enclose any number of <QPG:Rule> commands. As packager sorts the files, it checks them against each rule, in the order that the rules are specified. The file may match more than one rule.


Note: If you specify multiple rules in exactly the same way, they're merged into one entry. To prevent this behavior, add an xmlmultiple="true" attribute to each rule that might conflict with another.

When a rule is matched, the rule's attributes are copied into the file's attributes, thus redirecting it, renaming it, and so on. The following attributes aren't copied, because they're part of the rule itself:

Generating a repository

You can also use packager to generate a repository (a location holding any number of packages) and make it available to anyone who can access that repository. To do this, place all of your desired QPM and QPK files into the repository directory. (If you're working with QPR files, decompress them using tar -zxf my_package.qpr). Change directory into this repository and type packager -r.

The packager asks you a number of questions related to your repository, which you should answer fully. The description is the first thing a user sees after clicking on your repository, so it should be as detailed and accurate as possible.

As it generates your repository, packager creates the following files:

index
A list of the files in the repository.
content.tgz
An archive of all of the QPM files in the repository, which have been stripped of the file listing section (for faster downloading), including all support files such as licenses, scripts, and web pages.
repository.qrm
A repository manifest file with details about the number of packages in the repository, a website, icons, and a description of the repository.

Whenever you change the packages that appear in your repository, or when any packages are changed, you should again run packager -r in this directory. Once you've answered the questions, you won't have to answer them again, so you may wish to subsequently run the packager unattended and in expert mode, by typing packager -ruv2.

Hey, nice package!

There are many shortcuts that people take that make their packages reasonable and usable, but not necessarily complete. This section describes some tips and suggestions on how to make your packages better, along with some hints on how to modify your QPG to simplify package creation even further.

Product names and descriptions

What's the most obvious part of a package? It to be the things that users see when the package is presented to them: the product name and description.

The product name must be short, descriptive, and unique, so that no one will confuse your product with someone else's. Although we recommend that the product identifier be all in lowercase, for the product name, you should use an initial uppercase letter followed by lowercase, except where the product actually has explicit capitalization in its name (e.g. cURL).


Note: Don't put references to a processor or the version in the product name.

For example, here's a correctly presented product name:

<QPM:ProductName>Python<QPM:ProductName>

The product description is where you have to be most careful and succinct -- the old saying is true: first impressions are important. Here are some suggestions:

Reducing the number of packages created

After you've used packager, the first thing you might want to check is the list of packages that it created.

Quite often, packager creates more packages than you need for a simple product. For instance, if you have .h or .a files, packager creates separate Development packages to house these files, which are obviously for development purposes only. This is a useful feature, but if the product that you're packaging is inherently a development utility, separating the files into development and nondevelopment packages adds extra complexity that isn't needed.

The question you have to ask yourself is whether you want the user to be able to install just the executable portion, or to install just the development portion, without the other packages. If the answer is yes, then packager has done all the work for you. However, if there's no need for users to have this granularity, you should tell packager not to create separate development packages at all; the files will be merged into the other packages automatically. To achieve this, you can do one of these things:

Generating patches

A patch lets you release just the changes to a product instead of releasing a whole new version of it. You can tell packager to generate packages that contain only the files that have changed since the last full product release.

The patched packages are usually significantly smaller, so the user needs less disk space to keep both versions installed at once; to reinstate the original version, you need only deactivate -- not remove -- the patch. There are, however, some prerequisites to generating a patch:

To generate a patch, you need to have a QPP file. The QPP file indicates to packager where it can find your previously released product's QPR or QPK files, the version of the previously released product, and the date on which the product was released. You can generate a sample QPP file by typing packager -j4. The resulting file looks like this:

<QPP:Patches>
    <QPP:Release productid="pid" vendorid="vid">
        <QPP:File>mypackage-1.0.qpr</QPP:File>
        <QPP:Location>/home/package/directory/</QPP:Location>
        <QPP:Date>yyyymmddhh</QPP:Date>
        <QPP:Version>1.0</QPP:Version>
        <QPP:PatchIdentifier>patchA</QPP:PatchIdentifier>
        <QPP:Responsible>Guy Responsible</QPP:Responsible>
        <QPP:Email>gresponsible@home.com</QPP:Email>
        <QPP:Notes>Notes regarding this release</QPP:Notes>
    </QPP:Release>
</QPP:Patches>

Once you have the QPP file, modify it to match your product information:


Note: You can add any number of <QPP:Release> blocks, so you can use a single QPP to patch any number of products or in any number of packaging sessions. Each <QPP:Release> block must have a unique combination of productid and vendorid.

Once you've set up the QPP file properly, use the -h option to packager (along with whatever other arguments you would normally pass to the utility to generate an unpatched package), with your QPP file in order to indicate to packager that you're potentially generating a patch. For example:

packager -h my.qpp my.qpg

Remember that in my.qpg you must be generating a patch that's a different version from what you're patching. You usually set the <QPM:ReleaseVersion> to your original version, with an appended uppercase A, B, C, etc. (without any spaces) to make your new release version (e.g. the first patch to 5.7 would be 5.7A).

While packager works, it displays some messages related to patching:

Analyzing package
The packager displays this message for each original QPK that it's uncompressing into a temporary directory, where it then performs a file-by-file comparison with the new files. While this process is slower than regular packaging, it's time that's well spent on your machine rather than your users', because they'll have smaller packages to download and install.
[file has changed]
This is shown for each file that the packager determines is different from the original file.
A total of X files will be packaged as part of this patch.
The number of files that have been modified or added since the original release.
Warning: 'elfdiff' utility not available. Packager's patch comparison will be a full comparison of all files using the 'cmp' utility instead.
The elfdiff utility wasn't found on your system. This utility compares the ELF headers of executables so that the comparison process is faster, as compared to byte-by-byte comparison of files, but elfdiff isn't included in all versions of QNX.
Error: patch file not found
You have to pass the QPP filename along with the -h option.
No patch was required. Package not generated.
Either no files have changed since your original release, or no files have remained the same since your original release. Remember that at least one file, but not all files, must have changed for patching to proceed.

Note: Packages that had no changes between the original and the patch aren't generated. The generated packages have automatic dependencies on the original packages that you've patched, so the user needs only select your patch in order to gain a working product.


[Previous] [Contents] [Index] [Next]