GAP (ref) - Chapter 76: Using and Developing GAP Packages

Goto Chapter: Top 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 Bib Ind
[Top of Book] [Contents] [Previous Chapter] [Next Chapter]

[MathJax on]

76 Using and Developing GAP Packages
76.1 Installing a GAP Package
76.2 Loading a GAP Package
76.2-1 LoadPackage
76.2-2 Automatic loading of GAP packages
76.2-3 SetPackagePath
76.2-4 ExtendRootDirectories
76.2-5 ExtendPackageDirectories
76.2-6 DisplayPackageLoadingLog
76.3 Functions for GAP Packages
76.3-1 ReadPackage
76.3-2 TestPackageAvailability
76.3-3 IsPackageLoaded
76.3-4 IsPackageMarkedForLoading
76.3-5 TestPackage
76.3-6 InstalledPackageVersion
76.3-7 DirectoriesPackageLibrary
76.3-8 DirectoriesPackagePrograms
76.3-9 CompareVersionNumbers
76.3-10 DeclareAutoreadableVariables
76.3-11 Kernel modules in GAP packages
76.3-12 IsKernelExtensionAvailable
76.3-13 LoadKernelExtension
76.3-14 LoadDynamicModule
76.3-15 The PackageInfo.g File
76.3-16 ValidatePackageInfo
76.3-17 ShowPackageVariables
76.3-18 BibEntry
76.3-19 Cite
76.4 Guidelines for Writing a GAP Package
76.5 Structure of a GAP Package
76.6 Writing Documentation and Tools Needed
76.7 An Example of a GAP Package
76.8 File Structure
76.9 Creating the PackageInfo.g File
76.10 Functions and Variables and Choices of Their Names
76.11 Package Dependencies (Requesting one GAP Package from within Another)
76.12 External Dependencies (System packages needed by a GAP Package)
76.13 Extensions Provided by a Package
76.14 Declaration and Implementation Part of a Package
76.15 Autoreadable Variables
76.16 Standalone Programs in a GAP Package
76.16-1 Installation of GAP Package Binaries
76.16-2 Test for the Existence of GAP Package Binaries
76.16-3 Calling of and Communication with External Binaries
76.17 Having an InfoClass
76.18 The Banner
76.19 Version Numbers
76.20 Testing a GAP package
76.20-1 Tests files for a GAP package
76.20-2 Testing GAP package loading
76.20-3 LoadAllPackages
76.20-4 Testing a GAP package with the GAP standard test suite
76.21 Access to the GAP Development Version
76.22 Version control and continuous integration for GAP packages
76.23 Selecting a license for a GAP Package
76.24 Releasing a GAP Package
76.25 The homepage of a Package
76.26 Some things to keep in mind
76.27 Package release checklists
76.27-1 Checklist for releasing a new package
76.27-2 Checklist for upgrading the package for the next major release of GAP

### 76 Using and Developing GAP Packages

The functionality of GAP can be extended by loading GAP packages. The GAP distribution already contains all currently redistributed GAP packages in the `gap-4.16dev/pkg` directory.

GAP packages are written by (groups of) GAP users who may not necessarily be members of the GAP developer team. The responsibility and copyright of a GAP package remains with the original author(s).

GAP packages have their own documentation which is smoothly integrated into the GAP help system. (When GAP is started, `LoadPackageDocumentation` is called for all packages.)

All GAP users who develop new code are invited to share the results of their efforts with other GAP users by making the code and its documentation available in form of a package. Guidance on how to do this is available from the GAP website (https://www.gap-system.org) and in the GAP package Example (see https://www.gap-system.org/Packages/example.html).

The GAP development team will assist in making any new package suitable for distribution with GAP. It is also possible to submit a package to a formal refereeing process.

In this chapter we first describe how to use existing packages, and then provide guidelines for writing a GAP package.

#### 76.1 Installing a GAP Package

Before a package can be used it must be installed. A standard distribution of GAP already contains all the packages currently redistributed with GAP. This set of packages has been checked for compatibility with the system and with each other during release preparation. Most of the packages can be used immediately, but some of them may require further installation steps (see below).

Also, since GAP packages are released independently of the main GAP system, it may sometimes be useful to upgrade or install new packages between upgrades of your GAP installation, e.g. if a new version of a package adds new capabilities or bug fixes that you need.

A package consists of a collection of files within a single directory that must be a subdirectory of the `pkg` directory in one of the GAP root directories (see 9.2). If you don't have access to the `pkg` directory in your main GAP installation you can add private root directories as explained in section 9.2.

Whenever you download or clone an archive of a GAP package, it will contain a `README` file (or `README.md` etc.) that explains how it should be installed. Some packages just consist of GAP code and the installation is done by unpacking the archive in one of the places described above. There are also packages that need further installation steps, such as compilation or installing additional software to satisfy their dependencies. If there are some external programs which have to be compiled, this is often done by executing `./configure; make` inside the unpacked package directory (but check the individual `README` files).

Most of the packages that require compilation can be compiled in a single step by changing to the `pkg` directory of your GAP installation and calling the `../bin/BuildPackages.sh` script.

Note that if you use Windows you may not be able to use some or all external binaries.

#### 76.2 Loading a GAP Package

If a package is not already loaded, it may be loaded using the function `LoadPackage` (76.2-1).

Some GAP packages are prepared for automatic loading, that is they will be loaded automatically when GAP starts (see 76.2-2).

##### 76.2-1 LoadPackage

`‣ LoadPackage`( name[, version][, banner] ) | ( function )

loads the GAP package with name name.

As an example, the following loads the GAP package SONATA (case insensitive) which provides methods for the construction and analysis of finite nearrings:

    gap> LoadPackage("sonata");
    ... some more lines with package banner(s) ...
    true

The package name is case insensitive and may be appropriately abbreviated. At the time of writing, for example, `LoadPackage("semi");` will load the Semigroups package, and `LoadPackage("js");` will load the json package. If the abbreviation cannot be uniquely completed, a list of available completions will be offered, and `LoadPackage` returns `fail`. Thus the names of all installed packages can be shown by calling `LoadPackage("");`.

When the optional argument string version is present, the package will only be loaded in a version number equal to or greater than version (see `CompareVersionNumbers` (76.3-9)). If the first character of version is `=` then only that version will be loaded.

`LoadPackage` will return `true` if the package has been successfully loaded, and will return `fail` if the package could not be loaded. The latter may be the case if the package is not installed, if necessary binaries have not been compiled, or if the version number of the available version is too small. If the package cannot be loaded, `TestPackageAvailability` (76.3-2) can be used to find the reasons. Also, `DisplayPackageLoadingLog` (76.2-6) can be used to find out more about the failure. To see the problems directly, one can change the verbosity using the user preference `InfoPackageLoadingLevel`, see `InfoPackageLoading` (76.2-6) for details.

If the package name has already been loaded in a version number equal to or greater than version, `LoadPackage` returns `true` without doing anything else.

If the optional argument banner is present then it must be either `true` or `false`; in the latter case, the effect is that no package banner is printed.

After a package has been loaded, all its code becomes available to use with the rest of the GAP library.

##### 76.2-2 Automatic loading of GAP packages

When GAP is started some packages are loaded automatically, and these belong to two categories. The first are those packages which are needed to start GAP (at the present time, the only such package is GAPDoc). Their list is contained in `GAPInfo.Dependencies.NeededOtherPackages`. The second are packages which are loaded during GAP startup by default. The latter list may be obtained by calling `UserPreference("PackagesToLoad")` and is customisable as described in Section Reference: Configuring User preferences.

While GAP will not start if any of the packages from the former group is missing, loading of the packages from the latter group may be suppressed by using the `-A` command line option (see 3.1).

If for some reason you don't want certain packages to be automatically loaded, GAP provides three levels for disabling autoloading.

The autoloading of specific packages can be overwritten for the whole GAP installation by putting a file `NOAUTO` into a `pkg` directory that contains lines with the names of packages which should not be automatically loaded.

Furthermore, individual users can disable the autoloading of specific packages by putting the names of these packages into the list that is assigned to the user preference ExcludeFromAutoload, for example in the user's `gap.ini` file (see 3.2-1).

Using the `-A` command line option when starting GAP (see 3.1), automatic loading of packages is switched off for this GAP session.

In any of the above three cases, the packages listed in `GAPInfo.Dependencies.NeededOtherPackages` are still loaded automatically, and an error is signalled if any of these packages is unavailable.

See `SetPackagePath` (76.2-3) for a way to force the loading of a prescribed package version. See also `ExtendRootDirectories` (76.2-4) and `ExtendPackageDirectories` (76.2-5) for methods of adding directories containing packages after GAP has been started.

##### 76.2-3 SetPackagePath

`‣ SetPackagePath`( pkgname, pkgpath ) | ( function )

This function can be used to force GAP to load a particular version of a package, even though newer versions of the package are available.

Let pkgname and pkgpath be strings denoting the name of a GAP package and the path to a directory where a version of this package can be found (i. e., calling `Directory` (9.4-2) with the argument pkgpath will yield a directory that contains the file `PackageInfo.g` of the package).

If the package pkgname is already loaded with an installation path different from pkgpath then `SetPackagePath` signals an error. If the package pkgname is not yet loaded then `SetPackagePath` erases the information about available versions of the package pkgname, and stores the record that is contained in the `PackageInfo.g` file at pkgpath instead, such that only the version installed at pkgpath can be loaded with `LoadPackage` (76.2-1).

One should call `SetPackagePath` immediately before loading the package in question. Note that calling `ExtendPackageDirectories` (76.2-5) or `ExtendRootDirectories` (76.2-4) may change the available versions of the package pkgname.

##### 76.2-4 ExtendRootDirectories

`‣ ExtendRootDirectories`( paths ) | ( function )

Let paths be a list of strings that denote paths to intended GAP root directories (see 9.2). The function `ExtendRootDirectories` adds these paths to the global list `GAPInfo.RootPaths` and calls the initialization of available GAP packages, such that later calls to `LoadPackage` (76.2-1) will find the GAP packages that are contained in `pkg` subdirectories of the directories given by paths.

Note that the purpose of this function is to make GAP packages in the given directories available. It cannot be used to influence the start of GAP, because the GAP library is loaded before `ExtendRootDirectories` can be called (and because `GAPInfo.RootPaths` is not used for reading the GAP library).

##### 76.2-5 ExtendPackageDirectories

`‣ ExtendPackageDirectories`( paths ) | ( function )

Let paths be a list of strings that denote paths to intended GAP package directories (see 9.3). The function `ExtendPackageDirectories` adds these paths to the global list `GAPInfo.PackageDirectories` and calls the initialization of available GAP packages, such that later calls to `LoadPackage` (76.2-1) will find the GAP packages that are contained in the directories given by paths.

##### 76.2-6 DisplayPackageLoadingLog

`‣ DisplayPackageLoadingLog`( [severity] ) | ( function )

`‣ InfoPackageLoading` | ( info class )

`‣ PACKAGE_ERROR` | ( global variable )

`‣ PACKAGE_WARNING` | ( global variable )

`‣ PACKAGE_INFO` | ( global variable )

`‣ PACKAGE_DEBUG` | ( global variable )

`‣ LogPackageLoadingMessage`( severity, message[, name] ) | ( function )

Whenever GAP considers loading a package, log messages are collected in a global list. The messages for the current GAP session can be displayed with `DisplayPackageLoadingLog`. To each message, a severity is assigned, which is one of `PACKAGE_ERROR`, `PACKAGE_WARNING`, `PACKAGE_INFO`, `PACKAGE_DEBUG`, in increasing order. The function `DisplayPackageLoadingLog` shows only the messages whose severity is at most severity, the default for severity is `PACKAGE_WARNING`.

The intended meaning of the severity levels is as follows.

PACKAGE_ERROR

  should be used whenever GAP will run into an error during package loading, where the reason of the error shall be documented in the global list.

PACKAGE_WARNING

  should be used whenever GAP has detected a reason why a package cannot be loaded, and where the message describes how to solve this problem, for example if a package binary is missing.

PACKAGE_INFO

  should be used whenever GAP has detected a reason why a package cannot be loaded, and where it is not clear how to solve this problem, for example if the package is not compatible with other installed packages.

PACKAGE_DEBUG

  should be used for other messages reporting what GAP does when it loads packages (checking dependencies, reading files, etc.). One purpose is to record in which order packages have been considered for loading or have actually been loaded.

The log messages are created either by the functions of GAP's package loading mechanism or in the code of your package, for example in the `AvailabilityTest` function of the package's `PackageInfo.g` file (see 76.3-15), using `LogPackageLoadingMessage`. The arguments of this function are severity (which must be one of the above severity levels), message (which must be either a string or a list of strings), and optionally name (which must be the name of the package to which the message belongs). The argument name is not needed if the function is called from a call of a package's `AvailabilityTest` function (see 76.3-15) or is called from a package file that is read from `init.g` or `read.g`; in these cases, the name of the current package (stored in the record `GAPInfo.PackageCurrent`) is taken. According to the above list, the severity argument of `LogPackageLoadingMessage` calls in a package's `AvailabilityTest` function is either `PACKAGE_WARNING` or `PACKAGE_INFO`.

If you want to see the log messages already during the package loading process, you can set the level of the info class `InfoPackageLoading` to one of the severity values listed above; afterwards the messages with at most this severity are shown immediately when they arise. In order to make this work already for autoloaded packages, you can call `SetUserPreference("InfoPackageLoadingLevel", lev);` to set the desired severity level lev. This can for example be done in your `gap.ini` file, see Section 3.2-1.

#### 76.3 Functions for GAP Packages

The following functions are mainly used in files contained in a package and not by users of a package. They are needed to organise reading package files into GAP in the right order, performing maintenance tasks like building documentation and running package tests, checking package dependencies, etc. You will find further information about their use in Section 76.4 and subsequent sections.

##### 76.3-1 ReadPackage

`‣ ReadPackage`( [name, ]file ) | ( function )

`‣ RereadPackage`( [name, ]file ) | ( function )

Called with two strings name and file, `ReadPackage` reads the file file of the GAP package name, where file is given as a path relative to the home directory of name. Note that file is read in the namespace of the package, see Section 4.10 for details.

If only one argument file is given, this should be the path of a file relative to the `pkg` subdirectory of GAP root paths (see 9.2). Note that in this case, the package name is assumed to be equal to the first part of file, so the one argument form is not recommended.

The absolute path is determined as follows. If the package in question has already been loaded then the file in the directory of the loaded version is read. If the package is available but not yet loaded then the directory given by `TestPackageAvailability` (76.3-2) is used, without prescribed version number. (Note that the `ReadPackage` call does not force the package to be loaded.)

If the file is readable then `true` is returned, otherwise a warning is displayed (for `ReadPackage`) or `false` is returned (for `RereadPackage`).

Each of name and file should be a string. The name argument is case insensitive.

`RereadPackage` does the same as `ReadPackage`, except that also read-only global variables are overwritten (cf. `Reread` (9.8-11)).

##### 76.3-2 TestPackageAvailability

`‣ TestPackageAvailability`( name[, version][, checkall] ) | ( function )

For strings name and version, this function tests whether the GAP package name is available for loading in a version that is at least version, or equal to version if the first character of version is `=` (see `CompareVersionNumbers` (76.3-9) for further details about version numbers).

The result is `true` if the package is already loaded, `fail` if it is not available, and the string denoting the GAP root path where the package resides if it is available, but not yet loaded. So the package name is available if the result of `TestPackageAvailability` is not equal to `fail`.

If the optional argument checkall is `true` then all dependencies are checked, even if some have turned out to be not satisfied. This is useful when one is interested in the reasons why the package name cannot be loaded. In this situation, calling first `TestPackageAvailability` and then `DisplayPackageLoadingLog` (76.2-6) with argument `PACKAGE_INFO` (76.2-6) will give an overview of these reasons.

You should not call `TestPackageAvailability` in the test function of a package (the value of the component `AvailabilityTest` in the `PackageInfo.g` file of the package, see 76.3-15), because `TestPackageAvailability` calls this test function.

The argument name is case insensitive.

##### 76.3-3 IsPackageLoaded

`‣ IsPackageLoaded`( name[, version] ) | ( function )

For strings name and version, this function tests whether the GAP package name is already loaded in a version that is at least version, or equal to version if the first character of version is `=` (see `CompareVersionNumbers` (76.3-9) for further details about version numbers).

The result is `true` if the package is already loaded, `false` otherwise.

##### 76.3-4 IsPackageMarkedForLoading

`‣ IsPackageMarkedForLoading`( name, version ) | ( function )

This function can be used in the code of a package A for testing whether the package name in version version will be loaded after the `LoadPackage` (76.2-1) call for the package A has been executed. This means that the package name had been loaded before, or has been (directly or indirectly) requested as a needed or suggested package of the package A or of a package whose loading requested that A was loaded.

##### 76.3-5 TestPackage

`‣ TestPackage`( pkgname ) | ( function )

It is recommended that a GAP package specifies a standard test in its `PackageInfo.g` file. If pkgname is a string with the name of a GAP package, then `TestPackage(pkgname)` will check if this package is loadable and has the standard test, and will run this test in the current GAP session.

The output of the test depends on the particular package, and it also may depend on the current GAP session (loaded packages, state of the random sources, defined global variables etc.).

##### 76.3-6 InstalledPackageVersion

`‣ InstalledPackageVersion`( name ) | ( function )

If the GAP package with name name has already been loaded then `InstalledPackageVersion` returns the string denoting the version number of this version of the package. If the package is available but has not yet been loaded then the version number string for that version of the package that currently would be loaded. (Note that loading another package might force loading another version of the package name, so the result of `InstalledPackageVersion` will be different afterwards.) If the package is not available then `fail` is returned.

The argument name is case insensitive.

##### 76.3-7 DirectoriesPackageLibrary

`‣ DirectoriesPackageLibrary`( name[, path] ) | ( function )

takes the string name, a name of a GAP package, and returns a list that is either empty or contains one directory object `dir` that describes the place where the library functions of this GAP package should be located.

In the latter case, `dir` is the path subdirectory of a directory where the package name is installed, where the default for path is `"lib"`, and where the package directory belongs to the version of name that is already loaded or is currently going to be loaded or would be the first version GAP would try to load if no other version is explicitly prescribed. (If the package name is not yet loaded then we cannot guarantee that the directory belongs to a version that really can be loaded.)

Note that `DirectoriesPackageLibrary` is likely to be called in the `AvailabilityTest` function in the package's `PackageInfo.g` file (see 76.3-15).

As an example, the following returns a directory object for the library functions of the GAP package Example:

    gap> DirectoriesPackageLibrary( "Example", "gap" );
    [ dir("/home/werner/gap/4.0/pkg/example/gap/") ]

Observe that we needed the second argument `"gap"` here, since Example's library functions are in the subdirectory `gap` rather than `lib`.

In order to find a subdirectory deeper than one level in a package directory, the second argument is again necessary whether or not the desired subdirectory relative to the package's directory begins with `lib`. The directories in path should be separated by `/` (even on systems, like Windows, which use `\` as the directory separator). For example, suppose there is a package `somepackage` with a subdirectory `m11` in the directory `data`, then we might expect the following:

    gap> DirectoriesPackageLibrary( "somepackage", "data/m11" );
    [ dir("/home/werner/gap/4.0/pkg/somepackage/data/m11") ]

##### 76.3-8 DirectoriesPackagePrograms

`‣ DirectoriesPackagePrograms`( name ) | ( function )

returns a list that is either empty or contains one directory object `dir` that describes the place where external binaries of the GAP package name should be located.

In the latter case, `dir` is the `bin/`architecture subdirectory of a directory where the package name is installed, where architecture is the architecture on which GAP has been compiled (this can be accessed as `GAPInfo.Architecture`, see `GAPInfo` (3.5-1)), and where the package directory belongs to the version of name that is already loaded or is currently going to be loaded or would be the first version GAP would try to load if no other version is explicitly prescribed. (If the package name is not yet loaded then we cannot guarantee that the directory belongs to a version that really can be loaded.)

Note that `DirectoriesPackagePrograms` is likely to be called in the `AvailabilityTest` function in the package's `PackageInfo.g` file (see 76.3-15).

    gap> DirectoriesPackagePrograms( "nq" );
    [ dir("/home/gap/4.0/pkg/nq/bin/x86_64-pc-linux-gnu-default64-kv3/") ]

##### 76.3-9 CompareVersionNumbers

`‣ CompareVersionNumbers`( supplied, required[, "equal"] ) | ( function )

A version number is a string which contains nonnegative integers separated by non-numeric characters. Examples of valid version numbers are for example:

    "1.0"   "3.141.59"  "2-7-8.3" "5 release 2 patchlevel 666"

`CompareVersionNumbers` compares two version numbers, given as strings. They are split at non-digit characters, the resulting integer lists are compared lexicographically. The routine tests whether supplied is at least as large as required, and returns `true` or `false` accordingly. A version number ending in `dev` is considered to be infinite.

##### 76.3-10 DeclareAutoreadableVariables

`‣ DeclareAutoreadableVariables`( pkgname, filename, varlist ) | ( function )

Let pkgname be the name of a package, let filename be the name of a file relative to the home directory of this package, and let varlist be a list of strings that are the names of global variables which get bound when the file is read. `DeclareAutoreadableVariables` notifies the names in varlist such that the first attempt to access one of the variables causes the file to be read.

##### 76.3-11 Kernel modules in GAP packages

If the package has a kernel module, then it can be compiled using the gac script. A kernel module is implemented in C and follows certain conventions to comply with the GAP kernel interface, which we plan to document later. In the meantime, we advice to get in touch with GAP developers if you plan to develop such a package.

To use the gac script to produce dynamically loadable modules, call it with the `-d` option, for example:

    $ gap4/gac -d test.c

This will produce a file `test.so`, which then can be loaded into GAP with `LoadKernelExtension` (76.3-13). If the kernel module is required for the package to work, then its `PackageInfo.g` should define a `AvailabilityTest` which calls `IsKernelExtensionAvailable` (76.3-12), see 76.16-2 for details.

Note that before GAP 4.12, `LoadDynamicModule` (76.3-14) was used for this. It is still available and in fact `LoadKernelExtension` (76.3-13) call it; but the latter provides a higher level abstraction and is more convenient to use.

##### 76.3-12 IsKernelExtensionAvailable

`‣ IsKernelExtensionAvailable`( pkgname[, modname] ) | ( function )

For use by packages: Search for a loadable kernel module inside package pkgname with name modname and return `true` if found, otherwise `false`. If modname is omitted, then pkgname is used instead. Note that package names are case insensitive, but modname is not.

This function first appeared in GAP 4.12. It is typically called in the `AvailabilityTest` function of a package (see 76.16-2).

    gap> IsKernelExtensionAvailable("myPackageWithKernelExtension");
    true

##### 76.3-13 LoadKernelExtension

`‣ LoadKernelExtension`( pkgname[, modname] ) | ( function )

For use by packages: Search for a loadable kernel module inside package pkgname with name modname, and load it if found. If modname is omitted, then pkgname is used instead. Note that package names are case insensitive, but modname is not.

This function first appeared in GAP 4.12. It is typically called in the `init.g` file of a package.

Previously, packages with a kernel module typically used code like this:

    path := Filename(DirectoriesPackagePrograms("SomePackage"), "SomePackage.so");
    if path <> fail then
      LoadDynamicModule(path);
    fi;

That can now be replaced by the following, which also produces more helpful error messages for the user:

    LoadKernelExtension("SomePackage");

For packages where the name of the kernel extension is not identical to that of the package, you can either rename the kernel extension to have a matching name (recommended if you only have a single kernel extension in your package, which is how we recommend to set up things anyway), or else use the two argument version:

    LoadKernelExtension("SomePackage", "kext"); # this will look for kext.so

##### 76.3-14 LoadDynamicModule

`‣ LoadDynamicModule`( filename ) | ( function )

To load a compiled file, the command `LoadDynamicModule` is used. This command loads filename as module.

    gap> LoadDynamicModule("./test.so");

On some operating systems, once you have loaded a dynamic module with a certain filename, loading another with the same filename will have no effect, even if the file on disk has changed.

##### 76.3-15 The PackageInfo.g File

Each package has the file `PackageInfo.g` which contains meta-information about the package (package name, version, author(s), relations to other packages, homepage, download archives, etc.). This file is used by the package loading mechanism, by the GAP webpages about packages, and also for the redistribution of a package with GAP.

A `PackageInfo.g` file contains a call to the function `SetPackageInfo`, with argument a record. The following components of this record are mandatory.

`PackageName`

  a nonempty string denoting the name of the package,

`Subtitle`

  a string that describes the package's contents, may be used by a default banner or on a web page, should fit on one line,

`Version`

  a nonempty string that does not start with `=`, denoting the version number of the package (see Section 76.19),

`Date`

  a string of the form `yyyy-mm-dd` denoting the release date of the current version of the package (a date since 1999, when GAP 4 appeared),

`License`

  a nonempty string containing an SPDX ID (see Section 76.23),

`ArchiveURL`

  a string started with `http://`, `https://`, or `ftp://`, denoting an URL from where the current package archive can be downloaded, but without the suffix describing the format (see the `ArchiveFormats` component),

`ArchiveFormats`

  a string that lists the supported formats (among `.tar.gz`, `.tar.bz2`, `-win.zip`), separated by whitespace or commas,

`README_URL`

  a string started with `http://`, `https://`, or `ftp://`, denoting an URL from where the current `README.md` or `README` file of the package can be downloaded,

`PackageInfoURL`

  a string started with `http://`, `https://`, or `ftp://`, denoting an URL from where the current `PackageInfo.g` file of the package can be downloaded,

`AbstractHTML`

  a string that describes the package's contents in a few lines, in HTML format; this text will be displayed on the package overview web page of GAP,

`PackageWWWHome`

  a string started with `http://`, `https://`, or `ftp://`, denoting the address of the package's home page,

`PackageDoc`

  a record or a list of records; each record describes a book of the package documentation, with the following components

  `BookName`

    a string, the name of the book,

  `LongTitle`

    a string shown by `?books`,

  `SixFile`

    a string denoting a relative path to the `manual.six` file of the book,

  `HTMLStart`

    a string denoting a relative path to the start file of the HTML version of the book,

  `PDFFile`

    a string denoting a relative path to the `.pdf` file of the book,

  `ArchiveURLSubset`

    a list of strings denoting relative paths to those files and directories from the archive that are needed for the online manual; typically, `[ "doc" ]` suffices,

The following components of the record are optional.

`TextFiles` or `BinaryFiles` or `TextBinaryFilesPatterns`

  a list of strings that specify which files in the archive are text files or binary files (at most one of the three components can be available, each string in `TextBinaryFilesPatterns` must start with `T` for text files and by `B` for binary files),

`Persons`

  a list of records, each with the mandatory components

  `LastName`

    a string,

  at least one of `IsAuthor` or `IsMaintainer`

    `true` or `false`,

  and optional components

  `FirstNames`

    a string (was mandatory before GAP 4.14),

  `Place`

    a string,

  `Institution`

    a string,

  If the `IsMaintainer` value is `true` then also one of the following components is mandatory, otherwise these components are optional.

  `Email`

    a string,

  `WWWHome`

    a string denoting an URL, or

  `PostalAddress`

    a string.

`SourceRepository`

  a record with the components `Type` (the version control system, e.g. `"git"` or `"hg"`) and `URL` (the URL of the repository), both strings,

`IssueTrackerURL`

  a string started with `http://`, `https://`, or `ftp://`,

`SupportEmail`

  a string denoting an e-mail address,

`Dependencies`

  a record describing the dependencies of the package (see Section 76.11), with the following optional components

  `GAP`

    a string denoting the needed version of GAP,

  `NeededOtherPackages`

    a list of pairs `[ pkgname, pkgversion ]` of strings, denoting the other packages which must be available if the current package shall be loadable,

  `SuggestedOtherPackages`

    a list of pairs `[ pkgname, pkgversion ]` of strings, denoting the other packages which shall be loaded together with the current package if they are available,

  `TestPackages`

    a list of pairs `[ pkgname, pkgversion ]` of strings, denoting packages that are needed only to test the package, but not to load the package,

  `NeededSystemPackages`

    a record whose contents describe external dependencies of the package in a machine-readable form (see 76.12 for more information),

  `ExternalConditions`

    a list of strings or of pairs `[ text, URL ]` of strings, denoting conditions on external programs in a human-readable form (see 76.12 for more information),

`AvailabilityTest`

  a function with no arguments that returns `true` if the package is available, and `false` otherwise (can be `ReturnTrue` (5.4-1) if the package consists only of GAP code; this is also the default value),

`BannerString` or `BannerFunction`

  a string or a function, respectively, that is used to create a package banner different from the default banner (see Section 76.18),

`TestFile`

  a string denoting a relative path to a readable file which contains tests of the package's functionality (see Section 76.20),

`Keywords`

  a list of strings that are keywords related to the topic of the package,

`Extensions`

  a list of records that describe conditional extensions of the package (see Section 76.13).

Other components of the record can be supported; for example, `AutoDoc` is used by the AutoDoc package if applicable.

##### 76.3-16 ValidatePackageInfo

`‣ ValidatePackageInfo`( info ) | ( function )

This function is intended to support package authors who create or modify `PackageInfo.g` files. (It is not called when these files are read during the startup of GAP or when packages are actually loaded.)

The argument info must be either a record as is contained in a `PackageInfo.g` file or a string which describes the path to such a file. The result is `true` if the record or the contents of the file, respectively, has correct format, and `false` otherwise; in the latter case information about the incorrect components is printed. These diagnostic messages can be suppressed by setting the global option `quiet` to `true`.

Note that the components used for package loading are checked as well as the components that are needed for composing the package overview web page or for updating the package archives.

If info is a string then `ValidatePackageInfo` checks additionally whether those package files exist that are mentioned in the file `info`, for example the `manual.six` file of the package documentation.

##### 76.3-17 ShowPackageVariables

`‣ ShowPackageVariables`( pkgname[, version][, arec] ) | ( function )

`‣ PackageVariablesInfo`( pkgname, version ) | ( function )

Let pkgname be the name of a GAP package. If the package pkgname is available but not yet loaded then `ShowPackageVariables` prints a list of global variables that become bound and of methods that become installed when the package is loaded. (For that, GAP actually loads the package.)

If a version number version is given (see Section Reference: Version Numbers) then this version of the package is considered.

An error message is printed if (the given version of) the package is not available or already loaded.

Information is printed about new and redeclared global variables, and about names of global variables introduced in the package that differ from existing globals only by case; note that the GAP help system is case insensitive, so it is difficult to document identifiers that differ only by case.

Info lines for undocumented variables are marked with an asterisk `*`.

The following entries are omitted from the list: default setter methods for attributes and properties that are declared in the package, and `Setattr` and `Hasattr` type variables where attr is an attribute or property.

The output can be customized using the optional record arec, the following components of this record are supported.

`show`

  a list of strings describing those kinds of variables which shall be shown, such as `"new global functions"`; the default are all kinds that appear in the package,

`showDocumented`

  `true` (the default) if documented variables shall be shown, and `false` otherwise,

`showUndocumented`

  `true` (the default) if undocumented variables shall be shown, and `false` otherwise,

`showPrivate`

  `true` (the default) if variables from the package's name space (see Section 4.10) shall be shown, and `false` otherwise,

`Display`

  a function that takes a string and shows it on the screen; the default is `Print` (6.3-4), another useful value is `Pager` (2.4-1).

An interactive variant of `ShowPackageVariables` is the function `BrowsePackageVariables` (Browse: BrowsePackageVariables) that is provided by the GAP package Browse. For this function, it is not sensible to assume that the package pkgname is not yet loaded before the function call, because one might be interested in packages that must be loaded before Browse itself can be loaded. The solution is that `BrowsePackageVariables` (Browse: BrowsePackageVariables) takes the output of `PackageVariablesInfo` as its second argument. The function `PackageVariablesInfo` is used by both `ShowPackageVariables` and `BrowsePackageVariables` (Browse: BrowsePackageVariables) for collecting the information about the package in question, and can be called before the package Browse is loaded.

##### 76.3-18 BibEntry

`‣ BibEntry`( pkgname[, key] ) | ( function )

Returns: a string in BibXMLext format (see GAPDoc: The BibXMLext Format) that can be used for referencing the GAP system or a GAP package.

If the argument pkgname is the string `"GAP"`, the function returns an entry for the current version of GAP.

Otherwise, if a string pkgname is given, which is the name of a GAP package, an entry for this package is returned; this entry is computed from the `PackageInfo.g` file of the current version of the package, see `InstalledPackageVersion` (76.3-6). If no package with name pkgname is installed then the empty string is returned.

A string for a different version of GAP or a package can be computed by entering, as the argument pkgname, the desired record from the `PackageInfo.g` file. (One can access these records using the function `PackageInfo`.)

In each of the above cases, an optional argument key can be given, a string which is then used as the key of the BibTeX entry instead of the default key that is generated from the system/package name and the version number.

`BibEntry` requires the functions `FormatParagraph` (GAPDoc: FormatParagraph) and `NormalizedNameAndKey` (GAPDoc: NormalizedNameAndKey) from the GAP package GAPDoc.

The functions `ParseBibXMLextString` (GAPDoc: ParseBibXMLextString) and `StringBibXMLEntry` (GAPDoc: StringBibXMLEntry) can be used to create for example a BibTeX entry from the return value, as follows.

    gap> bib:= BibEntry( "GAP", "GAP4.5" );;
    gap> Print( bib, "\n" );
    <entry id="GAP4.5"><misc>
      <title><C>GAP</C> &ndash; <C>G</C>roups, <C>A</C>lgorithms,
             and <C>P</C>rogramming, <C>V</C>ersion 4.5.1</title>
      <howpublished><URL>https://www.gap-system.org</URL></howpublished>
      <key>GAP</key>
      <keywords>groups; *; gap; manual</keywords>
      <other type="organization">The GAP <C>G</C>roup</other>
    </misc></entry>
    gap> parse:= ParseBibXMLextString( bib );;
    gap> Print( StringBibXMLEntry( parse.entries[1], "BibTeX" ) );
    @misc{ GAP4.5,
      title =            {{GAP}   {\textendash}   {G}roups,   {A}lgorithms,  and
                          {P}rogramming, {V}ersion 4.5.1},
      organization =     {The GAP {G}roup},
      howpublished =     {\href                      {https://www.gap-system.org}
                          {\texttt{https://www.gap-system.org}}},
      key =              {GAP},
      keywords =         {groups; *; gap; manual}
    }

##### 76.3-19 Cite

`‣ Cite`( [pkgname[, key]] ) | ( function )

Used with no arguments or with argument `"GAP"` (case-insensitive), `Cite` displays instructions on citing the version of GAP that is being used. Suggestions are given in plain text, HTML, BibXML and BibTeX formats. The same instructions are also contained in the `CITATION` file in the GAP root directory.

If pkgname is the name of a GAP package, instructions on citing this package will be displayed. They will be produced from the `PackageInfo.g` file of the working version of this package that must be available in the GAP installation being used. Otherwise, one will get a warning that no working version of the package is available.

The optional 2nd argument key has the same meaning as in `BibEntry` (76.3-18).

#### 76.4 Guidelines for Writing a GAP Package

The remaining part of this chapter explains the basics of how to write a GAP package so that it integrates properly into GAP.

There are two basic aspects of creating a GAP package.

First, it is a convenient possibility to load additional functionality into GAP including a smooth integration of the package documentation. Second, a package is a way to make your code available to other GAP users.

Moreover, the GAP Group may provide some help with redistributing your package via the GAP website after checking if the package provides some new or improved functionality which looks interesting for other users, if it contains reasonable documentation, and if it seems to work smoothly with the GAP library and other distributed packages. In this case the package can take part in the GAP distribution update mechanism and becomes a deposited package.

Furthermore, package authors are encouraged to check if the package would be appropriate for the refereeing process and submit it. If the refereeing has been successful, the package becomes an accepted package. Check out https://www.gap-system.org/Packages/Authors/authors.html on the GAP website for more details.

Below we start with a description how the directory structure of a GAP package should be constructed and then add remarks on certain aspects of creating a package, some of these only apply to some packages. Finally, we provide guidelines for the release preparation and its distribution.

#### 76.5 Structure of a GAP Package

A GAP package should have an alphanumeric name; mixed case is fine, but there should be no whitespace characters. All files of a GAP package packagename must be collected in a single directory packagedir, where packagedir should be just packagename optionally converted to lowercase and optionally followed by the package version (with or without hyphen to separate the version from packagename). Let us call this directory the home directory of the package.

To use the package with GAP, the directory packagedir must be a subdirectory of a `pkg` directory in (one of) the GAP root directories (see 9.2). For example, if GAP is installed in `/usr/local/gap4` then the files of the package `MyPack` may be placed in the directory `/usr/local/gap4/pkg/mypack`. The directory packagedir preferably should have the following structure (below, a trailing `/` distinguishes directories from ordinary files):

    packagedir/
      doc/
      lib/
      tst/
      CHANGES
      LICENSE
      README
      PackageInfo.g
      init.g
      read.g

This layout of directories and files may be created manually, or automatically using the tool called PackageMaker, available at https://github.com/gap-system/PackageMaker. The PackageMaker asks several questions about the intended package and then creates a new directory for it and populates it with all the files needed for a basic package.

Packages that contain some code that requires compilation will usually have it in the `src` subdirectory. They may also have extra files such as `configure`, `Makefile.in` etc. that automate the build procedure. There are three file names with a special meaning in the home directory of a package: `PackageInfo.g` and `init.g` which must be present, and `read.g` which is optional.

On the other hand, the names of `CHANGES`, `LICENSE` and `README` files are not strictly fixed. They may have extensions `.txt` or `.md`, and instead of `LICENSE` one could use e.g. `COPYING` or `GPL` for packages distributed under the GNU General Public License, or use `HISTORY` instead of `CHANGES`.

We now describe the above files and directories in more details:

`README`

  The filename may optionally have an extension, e.g. `.txt` or `.md`.

  This should contain how to get it instructions (covering the way of getting it with the GAP distribution and from the GAP website, if applicable), as well as installation instructions and names of the package authors and their email addresses. These installation instructions should be repeated or referenced from the package's documentation, which should be in the `doc` directory (see 76.6). Authors' names and addresses should be repeated both in the package's documentation and in the `PackageInfo.g` (see below).

`CHANGES`

  For further versions of the package, it will be also useful to have a `CHANGES` file that records the main changes between versions of the package.

  The filename may optionally have an extension, e.g. `.txt` or `.md`.

`LICENSE`

  The file which explains conditions on which the package is distributed.

  We advise all package authors to make clear in the documentation of their package the basis on which it is being distributed to users. Technically, this is the terms of the license which you give the users to copy, modify and redistribute your software (of which you presumably own the copyright) for their purposes.

  GAP itself is distributed under the GNU General Public License version 2, a popular free software license which allows users to redistribute it freely under the same terms, and requires that any software which incorporates GAP (technically, any derived work) also be distributed under those terms. We would encourage you to consider the GPL for your packages, but you might wish to be more restrictive (for instance forbidding redistribution for profit) or less restrictive (allowing your software to be incorporated into commercial software).

  The filename may optionally have an extension, e.g. `.txt` or `.md`. Some packages also use different filenames, like `COPYING`.

`configure`, `Makefile.in`

  These files are typically only used by packages which have a non-GAP component, e.g. some C code (the files of which should be in the `src` directory). The `configure` and `Makefile.in` files of the Example package provide prototypes (or they may be created using the PackageMaker mentioned above). The `configure` file typically takes a path path to the GAP root directory as argument and uses the value assigned to `GAParch` in the file `sysinfo.gap`, created when GAP was compiled to determine the compilation architecture, inserts this in place of the string `@GAPARCH@` in `Makefile.in` and creates a file `Makefile`. When `make` is run (which, of course, reads the constructed `Makefile`), a directory `bin` (if necessary) and subdirectories of `bin` with the path equal to the string assigned to `GAParch` in the file `sysinfo.gap` should be created; any binaries constructed by compiling the code in `src` should end up in this subdirectory of `bin`.

`PackageInfo.g`

  Every GAP package must have a `PackageInfo.g` file which contains meta-information about the package (package name, version, author(s), relations to other packages, homepage, download archives, etc.). This information is used by the package loading mechanism and also for the redistribution of a package with GAP. The Example package's `PackageInfo.g` file is well-commented and can be used as a prototype (see also 76.3-15 for further details). It may also be created using the PackageMaker mentioned above.

`init.g`, `read.g`

  A GAP package must have a file `init.g`. Typical `init.g` and `read.g` files should normally consist entirely of `ReadPackage` (76.3-1) commands (and possibly also `Read` (9.8-1) commands) for reading further files of the package. If the declaration and implementation parts of the package are separated (and this is recommended), there should be a `read.g` file. The declaration part of a package consists of function and variable name declarations and these go in files with `.gd` extensions; these files are read in via `ReadPackage` commands in the `init.g` file. The implementation part of a package consists of the actual definitions of the functions and variables whose names were declared in the declaration part, and these go in files with `.gi` extensions; these files are read in via `ReadPackage` commands in the `read.g` file. The reason for following the above dichotomy is that the `read.g` file is read after the `init.g` file, thus enabling the possibility of a function's implementation to refer to another function whose name is known but is not actually defined yet (see 76.14 below for more details).

  The GAP code (whether or not it is split into declaration and implementation parts) should go in the package's `lib` directory (see below).

`doc`

  This directory should contain the package's documentation, written in an XML-based documentation format supported by the GAP package GAPDoc (see GAPDoc: Introduction and Example) which is used for the GAP documentation itself.

  The Example package's documentation (see its `doc` directory) may be used as a prototype. It consists of the master file `main.xml`, further `.xml` files for manual chapters (included in the manual via `Include` directives in the master file) and the GAP input file `../makedocrel.g` which generates the manuals. Generally, one should also provide a `manual.bib` BibTeX database file or an `xml` file in the BibXMLext format (see GAPDoc: The BibXMLext Format).

  One could also use the AutoDoc which simplifies writing documentation by generating most of the GAPDoc code automatically.

`lib`

  This is the preferred place for the GAP code of the package, i.e. the `.g`, `.gd` and `.gi` files (other than `PackageInfo.g`, `init.g` and `read.g`). For some packages, the directory `gap` has been used instead of `lib`; `lib` has the advantage that it is the default subdirectory of a package directory searched for by the `DirectoriesPackageLibrary` (76.3-7) command.

`src`

  If the package contains non-GAP code, e.g. C code, then this source code should go in the `src` directory. If there are `.h` include files you may prefer to put these all together in a separate `include` directory. There is one further rule for the location of kernel library modules or external programs which is explained in 76.16-1 below.

`tst`

  It is highly recommended that a package should have test files, which then should go in the `tst` directory. For a deposited package, a test file with a basic test of the package (for example, to check that it works as expected and/or that the manual examples are correct) may be specified in the `PackageInfo.g` to be included in the GAP standard test suite and run as a part of the GAP release preparation. More specific and time consuming tests are not supposed to be a part of the GAP standard test suite but may be placed in the `tst` directory with further instructions on how to run them. See Section 76.20 about the requirements to the test files formats and further recommendations.

All other files can be organised as you like. But we suggest that you have a look at existing packages and use a similar scheme, for example, put examples in the `examples` subdirectory, data libraries in extra subdirectories, and so on.

Sometimes there may be a need to include an empty directory in the package distribution (for example, as a place to store some data that may appear at runtime). In this case package authors are advised to put in this directory a short `README` file describing its purpose to ensure that such directory will be included in the redistribution.

Concerning the GAP code in packages, it is recommended to use only documented GAP functions, see 83.3. In particular if you want to make your package available to other GAP users it is advisable to avoid using obsolete variables (see 77). To test that the package does not use obsolete variables you can set the `ReadObsolete` component in your `gap.ini` file to `false` (see 3.2) or start GAP with `-A -O` command line options (note that this may also cause problems with loading other packages that use obsolete variables).

#### 76.6 Writing Documentation and Tools Needed

If you intend to make your package available to other users it is essential to include documentation explaining how to install and use your programs.

Concerning the installation you should produce a `README` file which gives a short description of the purpose of the package and contains proper instructions how to install your package. Again, check out some existing packages to get an idea how this could look like.

Documentation for GAP package should be prepared in an XML-based documentation format that is defined in and can be used with the GAPDoc package (see GAPDoc: Introduction and Example).

There should be at least a text version of your documentation provided for use in the terminal running GAP and some nicely printable version in `.pdf` format. Many GAP users like to browse the documentation in HTML format via their web browser. As a package author, you are not obliged to provide an HTML version of your package manual, but if you use the GAPDoc package you should have no trouble in producing one.

Moreover, using the GAPDoc package, it is also possible to produce HTML version of the documentation supporting MathJax (https://www.mathjax.org/) for the high quality rendering of mathematical symbols while viewing it online. For example, if you are viewing the HTML version of the manual, compare how this formula will look with MathJax turned on/off:

[ χ, ψ ] = ( ∑_{g ∈ G} χ(g) ψ(g^{-1}) ) / |G|.

The manual of the Example package is written in the GAPDoc format, and commands needed to build it are contained in the file `makedocrel.g` (you don't need to re-build the manual since it is already included in the package). You will also need to have certain TeX tools installed: to produce manuals in the `.pdf` format, you need `pdflatex`.

In principle it is also possible to use alternative documentation systems. Historically, there is one such TeX-based system, which predates GAPDoc, and which is still in use by several packages. However, we do not recommend using it for new packages.

#### 76.7 An Example of a GAP Package

We illustrate the creation of a GAP package by an example of a very basic package.

Create the following directories in your home directory: `.gap`, `.gap/pkg` and `.gap/pkg/test`. Then inside the directory `.gap/pkg/test` create an empty file `init.g`, and a file `PackageInfo.g` with the following contents:

    SetPackageInfo( rec(
      PackageName := "test",
      Version := "1.0",
      PackageDoc := rec(
          BookName  := "test",
          SixFile   := "doc/manual.six",
      ),
      Dependencies := rec(
          GAP       := "4.9",
          NeededOtherPackages := [ ["GAPDoc", "1.6"] ],
          SuggestedOtherPackages := [ ] ),
      AvailabilityTest := ReturnTrue ) );

This file declares the GAP package with name test in version 1.0. The package documentation consists of one autoloaded book; the `SixFile` component is needed by the GAP help system. Package dependencies (picked for the purposes of this example) require at least GAP 4.9 and GAPDoc package at version at least 1.6, and these conditions will be checked when the package will be loaded (see 76.19). Since there are no requirements that have to be tested, `AvailabilityTest` just uses `ReturnTrue` (5.4-1).

Now start GAP (without using the `-r` option) and the `.gap` directory will be added to the GAP root directory to allow GAP to find the packages installed there (see 9.2).

    gap> LoadPackage("test");
    true

This GAP package is too simple to be useful, but we have succeeded in loading it via `LoadPackage` (76.2-1), satisfying all specified dependencies.

#### 76.8 File Structure

Package files may follow the style used for the GAP library. Every file in the GAP library starts with a header that lists the filename, copyright, a short description of the file contents and the original authors of this file, and ends with a comment line `#E`. Indentation in functions and the use of decorative spaces in the code are left to the decision of the authors of each file. Global (i.e. re-used elsewhere) comments usually are indented by two hash marks and two blanks, in particular, every declaration or method or function installation which is not only of local scope is separated by a header.

Facilities to distribute a document over several files to allow the documentation for parts of some code to be stored in the same file as the code itself are provided by the GAPDoc package (see GAPDoc: Distributing a Document into Several Files). The same approach is demonstrated by the Example package. E.g. `example/doc/example.xml` has the statement `<#Include Label="ListDirectory">` and `example/lib/files.gd` contains

    ##  <#GAPDoc Label="ListDirectory">
    ##  <ManSection>
    ##  <Func Name="ListDirectory" Arg="[dir]"/>
    ##
    ##  <Description>
    ##  lists the files in directory <A>dir</A> (a string)
    ##  or the current directory if called with no arguments.
    ##  </Description>
    ##  </ManSection>
    ##  <#/GAPDoc>
    DeclareGlobalFunction( "ListDirectory" );

This is all put together in the file `example/makedocrel.g` which builds the package documentation, calling `MakeGAPDocDoc` (GAPDoc: MakeGAPDocDoc) with locations of library files containing parts of the documentation.

Alternatively, one could use the AutoDoc, which simplifies writing documentation by generating most of the GAPDoc code automatically. The equivalent of the fragment of the code above for AutoDoc would look like

    #! @Arguments [dir]
    #! @Description
    #!  lists the files in directory <A>dir</A> (a string)
    #!  or the current directory if called with no arguments.
    DeclareGlobalFunction( "ListDirectory" );

#### 76.9 Creating the PackageInfo.g File

While the minimalistic `PackageInfo.g` file described in 76.7 is enough to let GAP load the package, and check all specified dependencies, it is actually missing many extra fields which become relevant if you want to distribute your package: they contain lists of authors and/or maintainers including contact information, URLs of the package archives and README files, status information, text for a package overview webpage, and so on. All these details are required for a package to be redistributed with GAP.

The command `ValidatePackageInfo` (76.3-16) can be used to get a quick idea about which fields are missing:

    gap> ValidatePackageInfo("PackageInfo.g");
    #E  component `Subtitle' must be bound to a string
    #E  component `Date' must be bound to a string of the form `dd/mm/yyyy'
    #E  component `ArchiveURL' must be bound to a string started with http://, https:// or ftp://
    #E  component `ArchiveFormats' must be bound to a string
    #E  component `README_URL' must be bound to a string started with http://, https:// or ftp://
    #E  component `PackageInfoURL' must be bound to a string started with http://, https:// or ftp://
    #E  component `AbstractHTML' must be bound to a string
    #E  component `PackageWWWHome' must be bound to a string started with http://, https:// or ftp://
    #E  component `ArchiveURLSubset' must be bound to a list of strings denoting relative paths to readable files or directories
    #E  component `HTMLStart' must be bound to a string denoting a relative path to a readable file
    #E  component `PDFFile' must be bound to a string denoting a relative path to a readable file
    #E  component `SixFile' must be bound to a string denoting a relative path to a readable file
    #E  component `LongTitle' must be bound to a string
    false

We suggest to create a `PackageInfo.g` file for your package by copying the one in the Example package, distributed with GAP, or using the PackageMaker (https://github.com/gap-system/PackageMaker), and then adjusting it for your package. Within GAP you can look at this template file for a list and explanation of all recognised entries by

    Pager(StringFile(Filename(DirectoriesLibrary(),
                              "../pkg/example/PackageInfo.g")));

Instead of populating the rest of the `PackageInfo.g` by hands, you can also create a basic GAP package with the help of the tool called PackageMaker, available at https://github.com/gap-system/PackageMaker. The PackageMaker asks several questions about the intended package and then creates a new directory for it and populates it with all the files needed for a basic package.

#### 76.10 Functions and Variables and Choices of Their Names

In writing the GAP code for your package you need to be a little careful on just how you define your functions and variables.

Firstly, in general one should avoid defining functions and variables via assignment statements in the way you would interactively, e.g.

    gap> Squared := x -> x^2;;
    gap> Cubed := function(x) return x^3; end;;

The reason for this is that such functions and variables are easily overwritten and what's more you are not warned about it when it happens.

To protect a function or variable against overwriting there is the function `BindGlobal` (4.9-8), or alternatively (and equivalently) you may define a global function via a `DeclareGlobalFunction` (79.10-5) and `InstallGlobalFunction` (79.10-5) pair or a global variable via a `DeclareGlobalVariable` (79.10-2) and `InstallValue` (79.10-3) pair. There are also operations and their methods, and related objects like attributes and filters which also have `Declare...` and `Install...` pairs.

Secondly, it is a good idea to reduce the chance of accidental overwriting by choosing names for your functions and variables that begin with a string that identifies it with the package, e.g. some of the undocumented functions in the Example package begin with `Eg`. This is especially important in cases where you actually want the user to be able to change the value of a function or variable defined by your package, for which you have used direct assignments (for which the user will receive no warning if she accidentally overwrites them). It is also important for functions and variables defined via `BindGlobal`, `DeclareGlobalFunction`/`InstallGlobalFunction` and `DeclareGlobalVariable`/`InstallValue`, in order to avoid name clashes that may occur with (extensions of) the GAP library and other packages.

Additionally, since GAP 4.5 a package may place global variables into a local namespace as explained in 4.10 in order to avoid name clashes and preserve compatibility. This new feature allows you to define in your package global variables with the identifier ending with the `@` symbol, e.g. `xYz@`. Such variables may be used in your package code safely, as they may be accessed from outside the package only by their full name, i.e. `xYz@YourPackageName`. This helps to prevent clashes between different packages or between a package and the GAP library because of the same variable names.

On the other hand, operations and their methods (defined via `DeclareOperation` (78.1-5), `InstallMethod` (78.3-1) etc. pairs) and their relatives do not need this consideration, as they avoid name clashes by allowing for more than one method for the same-named object.

To demonstrate the definition of a function via a `DeclareOperation`/`InstallMethod` pair, the method `Recipe` (Example: Recipe) was included in the Example package; `Recipe( FruitCake );` gives a method for making a fruit cake (forgive the pun).

Thirdly, functions or variables with `SetXXX` or `HasXXX` names (even if they are defined as operations) should be avoided as these may clash with objects associated with attributes or properties (attributes and properties XXX declared via the `DeclareAttribute` and `DeclareProperty` commands have associated with them testers of form `HasXXX` and setters of form `SetXXX`).

Fourthly, it is a good idea to have some convention for internal functions and variables (i.e. the functions and variables you don't intend for the user to use). For example, they might be entirely CAPITALISED.

Additionally, there is a recommended naming convention that the GAP core system and GAP packages should not use global variables starting in the lowercase. This allows to reserve variables with names starting in lowercase to the GAP user so they will never clash with the system. It is extremely important to avoid using for package global variables very short names started in lowercase. For example, such names like `cs`, `exp`, `ngens`, `pc`, `pow` which are perfectly fine for local variables, should never be used for globals. Additionally, the package must not have writable global variables with very short names even if they are starting in uppercase, for example, `C1` or `ORB`, since they also could be easily overwritten by the user.

It is a good practice to follow naming conventions used in GAP as explained in 5.6 and Tutorial: Changing the Structure, which might help users to memorize or even guess names of functions provided by the package.

Finally, note the advantage of using `DeclareGlobalFunction`/`InstallGlobalFunction`, `DeclareGlobalVariable`/`InstallValue`, etc. pairs (rather than `BindGlobal`) to define functions and variables, which allow the package author to organise her function- and variable- definitions in any order without worrying about any interdependence. The `Declare...` statements should go in files with `.gd` extensions and be loaded by `ReadPackage` statements in the package `init.g` file, and the `Install...` definitions should go in files with `.gi` extensions and be loaded by `ReadPackage` statements in the package `read.g` file; this ensures that the `.gi` files are read after the `.gd` files. All other package code should go in `.g` files (other than the `init.g` and `read.g` files themselves) and be loaded via `ReadPackage` statements in the `init.g` file.

In conclusion, here is some practical advice on how to check which variables are used by the package.

Firstly, there is a function `ShowPackageVariables` (76.3-17). If the package pkgname is available but not yet loaded then `ShowPackageVariables( pkgname )` prints a list of global variables that become bound and of methods that become installed when the package is loaded (for that, the package will be actually loaded, so `ShowPackageVariables` can be called only once for the same package in the same GAP session.) The second optional argument version may specify a particular package version to be loaded. An error message will be printed if (the given version of) the package is not available or already loaded.

Info lines for undocumented variables will be marked with an asterisk `*`. Note that the GAP help system is case insensitive, so it is difficult to document identifiers that differ only by case.

The following entries are omitted from the list: default setter methods for attributes and properties that are declared in the package, and `Setattr` and `Hasattr` type variables where attr is an attribute or property.

For example, for the Example package it may produce the output looking like this:

    gap> ShowPackageVariables("example");
    ----------------------------------------------------------------
    Loading Example 3.3 (Example/Template of a GAP Package)
    by Werner Nickel (http://www.mathematik.tu-darmstadt.de/~nickel),
       Greg Gamble (http://www.math.rwth-aachen.de/~Greg.Gamble), and
       Alexander Konovalov (http://www.cs.st-andrews.ac.uk/~alexk/).
    ----------------------------------------------------------------
    new global functions:
      EgSeparatedString( str, c )*
      FindFile( dir, file )
      HelloWorld(  )
      ListDirectory( arg )
      LoadedPackages(  )
      WhereIsPkgProgram( prg )
      Which( prg )

    new global variables:
      FruitCake

    new operations:
      Recipe( arg )

    new methods:
      Recipe( cake )

Another trick is to start GAP with `-r -A` options, immediately load your package and then call `NamesUserGVars` (4.9-11) which returns a list of the global variable names created since the library was read, to which a value is currently bound. For example, for the Example it produces

    gap> NamesUserGVars();
    [ "EgSeparatedString", "FindFile", "FruitCake", "HelloWorld", "ListDirectory",
      "LoadedPackages", "Recipe", "WhereIsPkgProgram", "Which" ]

but for packages with dependencies it will also contain variables created by other packages. Nevertheless, it may be a useful check to search for unwanted variables appearing after package loading. A potentially dangerous situation which should be avoided is when the package uses some simply named temporary variables at the loading stage. Such phantom variables may then remain unnoticed and, as a result, there will be no warnings if the user occasionally uses the same name as a local variable name in a function. Even more dangerous is the case when the user variable with the same name already exists before the package is loaded so it will be silently overwritten.

#### 76.11 Package Dependencies (Requesting one GAP Package from within Another)

It is possible for one GAP package `A` to require another package `B`. For that, one simply adds the name and the (least) version number of the package `B` to the `NeededOtherPackages` component of the `Dependencies` component of the `PackageInfo.g` file of the package `A`. In this situation, loading the package `A` forces that also the package `B` is loaded, and that `A` cannot be loaded if `B` is not available.

If `B` is not essential for `A` but should be loaded if it is available (for example because `B` provides some improvements of the main system that are useful for `A`) then the name and the (least) version number of `B` should be added to the `SuggestedOtherPackages` component of the `Dependencies` component of the `PackageInfo.g` file of `A`. In this situation, loading `A` forces an attempt to load also `B`, but `A` is loaded even if `B` is not available.

If `B` is not essential for `A` but is used in the package tests, (for example because `B` is a library of groups used to provide testcases) then the name and the (least) version number of `B` should be added to the `TestPackages` component of the `Dependencies` component of the `PackageInfo.g` file of `A`. Note that GAP itself does not use this information at all. In particular, no attempts are made to actually load `B`, this should be done explicitly as part of the package tests. The benefit of specifying this component is for automated test runners (e.g. as part of the GAP package distribution) which can use this information to ensure all packages needed to run your package's tests are installed and ready.

All package dependencies must be documented explicitly in the `PackageInfo.g` file. It is important to properly identify package dependencies and make the right decision whether the other package should be needed or suggested. For example, declaring package as needed when suggested might be sufficient may prevent loading of packages under Windows for no good reason.

It is not appropriate to explicitly call `LoadPackage` (76.2-1) when the package is loaded, since this may distort the order of package loading and result in warning messages. It is recommended to turn such dependencies into needed or suggested packages. For example, a package can be designed in such a way that it can be loaded with restricted functionality if another package (or standalone program) is missing, and in this case the missing package (or binary) is suggested. Alternatively, if the package author decides that loading the package in this situation makes no sense, then the missing component is needed.

On the other hand, if `LoadPackage` (76.2-1) is called inside functions of the package then there is no such problem, provided that these functions are called only after the package has been loaded, so it is not necessary to specify the other package as suggested. The same applies to test files and manual examples, which may be simply extended by calls to `LoadPackage` (76.2-1).

It may happen that a package B that is listed as a suggested package of package A is actually needed by A. If no explicit `LoadPackage` (76.2-1) calls for B occur in A at loading time, this can now be detected using the new possibility to load a package without loading its suggested packages using the global option `OnlyNeeded` which can be used to (recursively) suppress loading the suggested packages of the package in question. Using this option, one can check whether errors or warnings appear when B is not available (note that this option should be used only for such checks to simulate the situation when package B is not available; it is not supposed to be used in an actual GAP session when package B will be loaded later, since this may cause problems). In case of any errors or warnings, their consequence can then be either turning B into a needed package or (since apparently B was not intended to become a needed package) changing the code accordingly. Only if package A calls `LoadPackage` (76.2-1) for B at loading time (see above) then package B needs to be deinstalled (i.e. removed) to test loading of A without B.

#### 76.12 External Dependencies (System packages needed by a GAP Package)

It is possible for a GAP package to require external software. If this software is not bundled together with the package, then this dependency should be documented. To do so, one may add either a string describing the dependency, or a list `[ description, URL ]`, to the `ExternalConditions` component of the `Dependencies` component of the `PackageInfo.g` file of the GAP package.

    ExternalConditions := [
        [ "needs the PARI/GP computer algebra system Version 2.5 or higher",
          "https://pari.math.u-bordeaux.fr/" ]
    ]

Note that the data in `ExternalConditions` is purely informational and meant to be human-readable, not machine-readable. GAP itself does not use it, but for packages distributed with GAP, the GAP website displays it in its package list.

If this dependency is available through a package manager such as `apt` or `brew`, this should also be documented. This can be done by adding the system package to the relevant component (such as `Ubuntu` or `Homebrew`) of the `NeededSystemPackages` component of the `PackageInfo.g` file of the GAP package. Each system package is added by means of a list whose first component is the name needed by the package manager. The other elements of this list are reserved for future usage.

    NeededSystemPackages := rec(
        Ubuntu   := [["pari-gp"]],
        Homebrew := [["pari"]]
    )

Note that this mechanism is primarily intended for consumption by the GAP package distribution and by other testing tooling. It is deliberately kept very simple. For example, at this point there is no mechanism to prescribe a distribution version (basically, "Ubuntu" means whatever `ubuntu-latest` is referring to in GitHub actions), nor to specify a minimal version of a system package. Despite these strong limitations, this data may still be useful for people packaging GAP and its packages for a distribution, as it at least gives a hint which system packages may be needed.

#### 76.13 Extensions Provided by a Package

Sometimes a package `A` can provide additional functionality, such as better methods or additional data, if some other packages `B`, `C`, etc. are loaded. However, one would like package `A` to still be usable without these additional packages, and therefore `B`, `C`, etc. shall not be regarded as needed packages (see Section 76.11) of `A`.

One way to deal with this situation is to put those parts of code of `A` that depend on `B`, `C`, etc., into files that get read only in the situation that the packages in question have actually been loaded into the current GAP session.

However, this leaves the question when to load these files of a conditional extension of `A`. In the past, the only option for `A` was to check for the presence of `B`, `C`, etc., while it itself was being loaded. With this setup, it depends on the order in which packages get loaded whether some feature is available or not: If `B` is loaded before `A`, the extension might be loaded as well; if `B` is loaded only after `A`, then the extension is not loaded.

To deal with this issue of conditional extensions of packages, GAP offers a dedicated mechanism: The `Extensions` component of the `PackageInfo.g` file of `A` is a list of declarations of conditional extension of `A`, each being a record with the following components.

`needed`

  a list of the form `[ [ pkgname1, version1 ], [ pkgname2, version2 ],` ...`]`, meaning that the extension shall be loaded as soon as all packages `pkgname1`, `pkgname2`, ..., with versions (at least) `version1`, `version2`, ..., have been loaded, and

`filename`

  the path, relative to the package directory of `A`, of a file such that reading this file will load the code of the extension.

As an example suppose the following is part of the `PackageInfo.g`. Then GAP will load the file `fileForB.gd` as soon as package `B` is loaded in version 0.6 or newer, and `fileForCD.gi` once package `C` and `D` are loaded in version 1.2 and 0.1 or newer respectively.

    Extensions := [
      rec(
        needed := [ ["B", "0.6"] ],
        filename := "gap/fileForB.gd",
      ),
      rec(
        needed := [ ["C", "1.2"] , ["D", "0.1"] ],
        filename := "gap/fileForCD.gi",
      )
    ],

Whenever `LoadPackage` (76.2-1) is called, GAP checks for package extensions whose conditions now are satisfied, and loads them.

For example, package `A` can be loaded early in a GAP session, and declare in its `PackageInfo.g` the availability of an extension that requires package `B`. If `B` has not yet been loaded then this extension will not be loaded together with `A`. However, as soon as `B` gets (installed and) loaded later in the session, also the extension of `A` will automatically get loaded.

The contents of `Extensions` in a `PackageInfo.g` file does not affect the lists of needed or suggested packages. If an extension of `A` is beneficial for the functions of `A` then it makes sense to list the packages needed for the extension among the suggested packages of `A`, but this may not be the case if the extension is beneficial only for the functions of its needed packages.

#### 76.14 Declaration and Implementation Part of a Package

When GAP packages require each other in a circular way, a bootstrapping problem arises of defining functions before they are called. The same problem occurs in the GAP library, and it is resolved there by separating declarations (which define global variables such as filters and operations) and implementations (which install global functions and methods) in different files. Any implementation file may use global variables defined in any declaration file. GAP initially reads all declaration files (in the library they have a `.gd` suffix) and afterwards reads all implementation files (which have a `.gi` suffix).

Something similar is possible for GAP packages: if a file `read.g` exists in the home directory of the package, this file is read only after all the `init.g` files of all (implicitly) required GAP packages are read. Thus one can separate declaration and implementation for a GAP package in the same way as is done for the GAP library, by creating a file `read.g`, restricting the `ReadPackage` (76.3-1) statements in `init.g` to only read those files of the package that provide declarations, and to read the implementation files from `read.g`.

Examples:

Suppose that there are two packages `A` and `B`, each with files `init.g` and `read.g`.

- If package `A` suggests or needs package `B` and package `B` does not need or suggest any other package then first `init.g` of `B` is read, then `read.g` of `B`, then `init.g` of `A`, then `read.g` of `A`.

- If package `A` suggests or needs package `B` and package `B` (or a package that is suggested or needed by `B`) suggests or needs package `A` then first the files `init.g` of `A` and `B` are read (in an unspecified order) and then the files `read.g` of `A` and `B` (in the same order).

In general, when GAP is asked to load a package then first the dependencies between this packages and its needed and suggested packages are inspected (recursively), and a list of package sets is computed such that no cyclic dependencies occur between different package sets and such that no package in any of the package sets needs any package in later package sets. Then GAP runs through the package sets and reads for each set first all `init.g` files and then all `read.g` files of the packages in the set. (There is one exception from this rule: Whenever packages are autoloaded before the implementation part of the GAP library is read, only the `init.g` files of the packages are read; as soon as the GAP library has been read, the `read.g` files of these packages are also read, and afterwards the above rule holds.)

It can happen that some code of a package depends on the availability of suggested packages, i.e., different initialisations are performed depending on whether a suggested package will eventually be loaded or not. One can test this condition with the function `IsPackageMarkedForLoading` (76.3-4). In particular, one should not call (and use the value returned by this call) the function `LoadPackage` (76.2-1) inside package code that is read during package loading. Note that for debugging purposes loading suggested packages may have been deliberately disabled via the global option `OnlyNeeded`.

Note that the separation of the GAP code of packages into declaration part and implementation part does in general not allow one to actually call functions from a package when the implementation part is read. For example, in the case of a cyclic dependency as in the second example above, suppose that `B` provides a new function `f` or a new global record `r` which are declared in the declaration part of `B`. Then the code in the implementation part of `A` may contain calls to the functions defined in the declaration part of `B`. However, the implementation part of `A` may be read before the implementation part of `B`. So one can in general not assume that during the loading of `A`, the function `f` can be called, or that one can access components of the record `r`.

If one wants to call the function `f` or to access components of the record `r` in the code of the package `A` then the problem is that it may be not possible to determine a cyclic dependency between `A` and `B` from the packages `A` and `B` alone. A safe solution is then to design `A` in such a way that the code that calls `f` or accesses `r` belongs to package extensions of `A` that get loaded only after `B` has been loaded; see Section 76.13 for details.

In the case of cyclic dependencies, one solution for the above problem might be to delay those computations (typically initialisations) in package `A` that require package `B` to be loaded until all required packages are completely loaded. This can be done by moving the declaration and implementation of the variables that are created in the initialisation into a separate file and to declare these variables in the `init.g` file of the package, via a call to `DeclareAutoreadableVariables` (76.3-10) (see also 76.15).

#### 76.15 Autoreadable Variables

Package files containing method installations must be read when the package is loaded. For package files not containing method installations (this applies, for example, to many data files) another mechanism allows one to delay reading such files until the data are actually accessed. See 76.3-10 for further details.

#### 76.16 Standalone Programs in a GAP Package

GAP packages that involve stand-alone programs are fundamentally different from GAP packages that consist entirely of GAP code.

This difference is threefold: A user who installs the GAP package must also compile (or install) the package's binaries, the package must check whether the binaries are indeed available, and finally the GAP code of the package has to start the external binary and to communicate with it. We will cover these three points in the following sections.

If the package does not solely consist of an interface to an external binary and if the external program called is not just special-purpose code, but a generally available program, chances are high that sooner or later other GAP packages might also require this program. We therefore strongly recommend the provision of a documented GAP function that will call the external binary. We also suggest to create actually two GAP packages; the first providing only the binary and the interface and the second (requiring the first, see 76.11) being the actual GAP package.

##### 76.16-1 Installation of GAP Package Binaries

The scheme for the installation of package binaries which is described further on is intended to permit the installation on different architectures which share a common file system (and share the architecture independent file).

A GAP package which includes external binaries contains a `bin` subdirectory. This subdirectory in turn contains subdirectories for the different architectures on which the GAP package binaries are installed. The names of these directories must be the same as the names of the architecture dependent subdirectories of the main `bin` directory. Unless you use a tool like `autoconf` yourself, you must obtain the correct name of the binary directory from the main GAP branch. To help with this, the main GAP directory contains a file `sysinfo.gap` which assigns the shell variable `GAParch` to the proper name as determined by GAP's `configure` process. For example on a Linux system, the file `sysinfo.gap` may look like this:

    GAParch=i586-unknown-linux2.0.31-gcc

We suggest that your GAP package contains a file `configure` which is called with the path of the GAP root directory as parameter. This file then will read `sysinfo.gap` and set up everything for compiling under the given architecture (for example creating a `Makefile` from `Makefile.in`). As initial templates, you may use installation scripts of the Example package or files generated with the help of PackageMaker.

##### 76.16-2 Test for the Existence of GAP Package Binaries

If an external binary is essential for the workings of a GAP package, the function stored in the component `AvailabilityTest` of the `PackageInfo.g` file of the package should test whether the program has been compiled on the architecture (and inhibit package loading if this is not the case). This is especially important if the package is loaded automatically.

The easiest way to accomplish this is to use `Filename` (9.5-1) for checking for the actual binaries in the path given by `DirectoriesPackagePrograms` (76.3-8) for the respective package. For example the example GAP package could use the following function to test whether the binary `hello` has been compiled; it will issue a warning if not, and will only load the package if the binary is indeed available:

    ...
    AvailabilityTest := function()
      local path,file;
        # test for existence of the compiled binary
        path:= DirectoriesPackagePrograms( "example" );
        file:= Filename( path, "hello" );
        if file = fail then
          LogPackageLoadingMessage( PACKAGE_WARNING,
              [ "The program `hello' is not compiled,",
                "`HelloWorld()' is thus unavailable.",
                "See the installation instructions;",
                "type: ?Installing the Example package" ] );
        fi;
        return file <> fail;
      end,
    ...

However, if you look at the actual `PackageInfo.g` file of the example package, you will see that its `AvailabilityTest` function always returns `true`, and just logs the warning if the binary is not available (which may be later viewed with `DisplayPackageLoadingLog` (76.2-6)). This means that the binary is not regarded as essential for this package.

You might also have to cope with the situation that external binaries will only run under UNIX (and not e.g. under Windows), or may not compile with some compilers or default compiler options. See 3.4 for information on how to test for the architecture.

Package using a kernel module (see 76.3-11), one may use a test like this:

    ...
    AvailabilityTest := function()
        # see if example.so exists and is a loadable kernel extension
        if not IsKernelExtensionAvailable("example") then
          LogPackageLoadingMessage( PACKAGE_WARNING,
              [ "The kernel extension `example' is unavailable,",
                "perhaps it needs to be recompiled?",
                "See the installation instructions;",
                "type: ?Installing the Example package" ] );
          return false;
        fi;
        return true;
      end,
    ...

Last but not least: do not print anything in the `AvailabilityTest` function of the package via `Print` or `Info`. Instead one should call `LogPackageLoadingMessage` (76.2-6) to store a message which may be viewed later with `DisplayPackageLoadingLog` (76.2-6) (the latter two functions have been introduced in GAP 4.5)

##### 76.16-3 Calling of and Communication with External Binaries

There are two reasons for this: the input data has to be passed on to the stand-alone program and the stand-alone program has to be started from within GAP.

There are two principal ways of doing this.

The first possibility is to write all the data for the stand-alone to one or several files, then start the stand-alone with `Process` (11.1-1) or `Exec` (11.1-2) which then writes the output data to file, and finally read in the standalone's output file.

The second way is interfacing via input-output streams, see Section 10.8.

Some GAP packages use kernel modules (see 76.3-11) instead of external binaries. A kernel module is implemented in C and follows certain conventions to comply with the GAP kernel interface, which we plan to document later. In the meantime, we advise you to look at existing examples of such packages and get in touch with GAP developers if you plan to develop such a package.

#### 76.17 Having an InfoClass

It is a good idea to declare an `InfoClass` for your package. This gives the package user the opportunity to control the verbosity of output and/or the possibility of receiving debugging information (see 7.4). Below, we give a quick overview of its utility.

An `InfoClass` is defined with a `DeclareInfoClass( InfoPkgname );` statement and may be set to have an initial `InfoLevel` other than the zero default (which means no `Info` statement is to output information) via a `SetInfoLevel( InfoPkgname, level );` statement. An initial `InfoLevel` of 1 is typical.

`Info` statements have the form: `Info( InfoPkgname, level, expr1, expr2, ...);` where the expression list `expr1, expr2, ...` appears just like it would in a `Print` statement. The only difference is that the expression list is only printed (or even executed) if the `InfoLevel` of InfoPkgname is at least level.

#### 76.18 The Banner

When the package is loaded, GAP will display a default package banner, constructed from the package metadata provided in the `PackageInfo.g` file.

Alternatively, the package may establish its own banner by assigning either a string to the `BannerString` field of the record argument of `SetPackageInfo` in the `PackageInfo.g` file or a function to the `BannerFunction` field, which takes this record as its unique argument. The latter possibility can be useful if the banner shall show information that is available only at runtime.

If you will be designing a banner for your package, it is a good idea to suggest there how to access package documentation. For example, the banner of the Example package says:

    For help, type: ?Example package

In order for this to display the introduction of the Example package the index-entry `<Index>Example package</Index>` was added just before the first paragraph of the introductory section in the file `doc/example.xml` of the Example package.

#### 76.19 Version Numbers

Version numbers are strings containing nonnegative integers separated by non-numeric characters. They are compared by `CompareVersionNumbers` (76.3-9) which first splits them at non-digit characters and then lexicographically compares the resulting integer lists. Thus version `"2-3"` is larger than version `"2-2-5"` but smaller than `"4r2p3"` or `"11.0"`.

It is possible for code to require GAP packages in certain versions. In this case, all versions, whose number is equal or larger than the requested number are acceptable. It is the task of the package author to provide upwards compatibility.

Loading a specific version of a package (that is, not one with a larger version number) can be achieved by prepending `=` to the desired version number. For example, `LoadPackage( "example", "=1.0" )` will load version `"1.0"` of the package `"example"`, even if version `"1.1"` is available. As a consequence, version numbers must not start with `=`, so `"=1.0"` is not a valid version number.

Package authors should choose a version numbering scheme that admits a new version number even after tiny changes to the package, and ensure that version numbers of successive package versions increase. The automatic update of package archives in the GAP distribution will only work if a package has a new version number.

It is a well-established custom to name package archives like `name-version.tar.gz`, `name-version.tar.bz2` etc., where `name` is the lower case name, and `version` is the version (another custom is that the archive then should extract to a directory that has exactly the name `name-version`).

It is very important that there should not ever be, for a given GAP package, two different archives with the same package version number. If you make changes to your package and place a new archive of the package onto the public server, please ensure that a new archive has a new version number. This should be done even for very minor changes.

For most of the packages it will be inappropriate to re-use the date of the release as a version number. It is much more obvious how big are the changes between versions "4.4.12", "4.5.1" and "4.5.2" than between versions "2008.12.17", "2011.04.15" and "2011.09.14". The concept of using version numbers to convey the meaning of the status of the code and the way it has been modified is known as Semantic Versioning, see https://semver.org/ for further recommendations on its use.

Since version information is duplicated in several places throughout the package documentation, for GAPDoc-based manuals you may define the version and the release manual in the comments in `PackageInfo.g` file close to the place where you specified its `Version` and `Date` components, for example

    ##  <#GAPDoc Label="PKGVERSIONDATA">
    ##  <!ENTITY VERSION "3.3">
    ##  <!ENTITY RELEASEDATE "12/09/2017">
    ##  <!ENTITY RELEASEYEAR "2017">
    ##  <#/GAPDoc>

notify `MakeGAPDocDoc` (GAPDoc: MakeGAPDocDoc) that a part of the document is stored in `PackageInfo.g` (see `example/makedocrel.g`), read this data into the header of the main document via `<#Include Label="PKGVERSIONDATA">` directive and then use them via &VERSION; and &RELEASEDATE; entities almost everywhere where you need to refer to them (most commonly, in the title page and installation instructions).

#### 76.20 Testing a GAP package

There are several aspects of testing a GAP package.

First, one should ensure that the package functionality works as expected. Below we give an advice on creating test files for automated tests that may be run by package authors, by GAP developers as part of the release preparation, and by package users interested in checking that the package works. Such tests should be included in the package distribution, and the responsibility for ensuring that they pass stays with package authors.

Second, the package should cleanly integrate into the GAP system and other packages, and should not break their functionality. In particular, all tests from the standard GAP testing suite should pass if the package is loaded. This is more comprehensive and time consuming test, which GAP developers regularly run using special tools. They will report to you any detected issues. Below we explain how to do several simple and less time consuming checks which package authors are recommended to perform themselves.

##### 76.20-1 Tests files for a GAP package

The (optional) `tst` directory of your package may contain as many tests of the package functionality as appears appropriate. These tests should be organised into test files similarly to those in the `tst` directory of the GAP distribution as documented in 7.10.

For a deposited package, a test file with a basic test of the package (for example, to check that it works as expected and/or that the manual examples are correct) may be specified in the component `TestFile` in the `PackageInfo.g` to be included in the GAP standard test suite. This file can either consist of calls of `TestDirectory` (7.10-3) or `Test` (7.10-2) (in this case, it is common to call it `testall.g`) or be itself a test file having an extension `.tst` and supposed to be read via `Test` (7.10-2). It is assumed that the latter case occurs if and only if the file contains the substring

`"gap> START_TEST("`

(with exactly one space after the GAP prompt).

For deposited packages, these tests are run by the GAP Group regularly, as a part of the standard GAP test suite. For the efficient testing it is important that the test specified in the `PackageInfo.g` file does not display any output (e.g. no test progress indicators) except reporting discrepancies if such occur and the completion report as in the example below:

    gap> Test("tst/testall.tst");
    Example package: testall.tst
    true

Tests which produce extended output and/or require substantial runtime are not supposed to be a part of the GAP standard test suite but may be placed in the `tst` directory of the packages with further instructions on how to run them elsewhere.

Because of different approaches to testing, used by different packages, it is not always easy to identify whether an automated test passed or failed. Presently, automated detection works fine if a package uses a single `.tst` file or uses `TestDirectory` (7.10-3) with the `exitGAP` option set to `true` to run a collection of tests and then exits GAP in a way that allows an automated test setup to determine whether the test passed or failed:

    TestDirectory(DirectoriesPackageLibrary("packagename", "tst"), rec(exitGAP := true));

If one needs a more sophisticated test file, then it should end with an invocation of `ForceQuitGap` (6.7-4) with an argument that indicates whether the tests overall passed (`true`) or failed (`false` or `fail`). For example, if the test result is stored in a variable `testresult` then you can do this:

    ForceQuitGap(testresult);

##### 76.20-2 Testing GAP package loading

To test that your package may be loaded into GAP without any problems and conflicts with other packages, test that it may be loaded in various configurations:

- starting GAP with no packages (except needed for GAP) using `-r -A` options and calling `LoadPackage("packagename");`

- starting GAP with no packages (except needed for GAP) using `-r -A` options and calling `LoadPackage("packagename" : OnlyNeeded );`

- starting GAP in the default configuration (with no options) and calling `LoadPackage("packagename");`

- starting GAP in the default configuration (with no options) and calling `LoadPackage("packagename" : OnlyNeeded );`

- finally, together with all other packages using `LoadAllPackages` (76.20-3) (see below) in four possible combinations of starting GAP with/without `-r -A` options and calling `LoadAllPackages` (76.20-3) with/without `reversed` option.

The test of loading all packages is the most subtle one. Quite often it reveals problems which do not occur in the default configuration but may cause difficulties to the users of specialised packages.

Additionally, we recommend using `ShowPackageVariables` (76.3-17) to see information about variables created by your package to check if any have either short names (no more than three characters) or names breaking a recommended naming convention that the GAP core system. GAP packages also should not use global variables starting in the lowercase (see Section 76.10).

##### 76.20-3 LoadAllPackages

`‣ LoadAllPackages`( : reversed ) | ( function )

loads all GAP packages from their list sorted in alphabetical order (needed and suggested packages will be loaded when required). This is a technical function to check packages compatibility, so it should NOT be used to run anything except tests; it is known that GAP performance is slower if all packages are loaded. To introduce some variations of the order in which packages will be loaded for testing purposes, `LoadAllPackages` accepts option `reversed` to load packages from their list sorted in the reverse alphabetical order.

##### 76.20-4 Testing a GAP package with the GAP standard test suite

The `tst` directory of the GAP installation contains a selection of test files and scripts such as `testinstall.g` and `teststandard.g` which are a part of the GAP standard test suite.

It is important to check that your package does not break GAP standard tests. To perform a clean test and avoid interfering with other packages, first you must start a new GAP session and then read either `testinstall.g` or `teststandard.g` as demonstrated below.

The quicker test, `testinstall.g`, should run in about a minute depending on your hardware speed. It may be started with the command

    gap> Read( Filename( DirectoriesLibrary( "tst" ), "testinstall.g" ) );

You will get a large number of lines with output about the progress of the tests, for example:

    You should start GAP4 using `gap -A -x 80 -r'.

    Architecture: SOMETHING-SOMETHING-gcc-default64

    testing: ..../gap-4.X.Y/tst/testinstall/alghom.tst
          84 ms (55 ms GC) and 2.90MB allocated for alghom.tst
    testing: ..../gap-4.X.Y/tst/testinstall/algmat.tst
         839 ms (114 ms GC) and 219MB allocated for algmat.tst
    [ further lines deleted ]
    testing: ..../gap-4.X.Y/tst/testinstall/zmodnze.tst
         127 ms (119 ms GC) and 1.29MB allocated for zmodnze.tst
    -----------------------------------
    total     62829 ms (24136 ms GC) and 8.61GB allocated
                  0 failures in 252 files

    #I  No errors detected while testing

(optionally, you may start GAP with the command line options which you will see in the test output, to run it in a more conservative settings).

The more thorough test is `teststandard.g` which exercises more of GAP's capabilities, also including all test files from `teststandard.g`. It runs quite a bit longer, maybe 10-20 minutes, and produces an output similar to the testinstall.g test. To run it, also start a new GAP session and then call

    gap> Read( Filename( DirectoriesLibrary( "tst" ), "teststandard.g" ) );

You may repeat the same check loading your package with `OnlyNeeded` option. Remember to perform each subsequent test in a new GAP session.

Also you may perform individual tests from the `tst` directory of the GAP installation loading them with `Test` (7.10-2).

#### 76.21 Access to the GAP Development Version

We are aiming at providing a stable platform for package development and testing with official GAP releases. We also invite everyone to contribute by submitting patches, pull requests, and bug reports. We would like to make the contributing process as easy as possible.

The main GAP development repository is hosted on GitHub at https://github.com/gap-system/gap. Many GAP packages also have public repositories and issue trackers, and we are keeping a list of such packages at https://gap-packages.github.io/.

For further information about contributing to the GAP development, please see https://github.com/gap-system/gap/blob/master/CONTRIBUTING.md.

#### 76.22 Version control and continuous integration for GAP packages

As we have mentioned above, many GAP packages have public repositories and issue trackers on GitHub, and we are keeping a list of such packages at https://gap-packages.github.io/. We welcome establishing public repositories for new packages and migrating existing package repositories there as well. Such repositories may be hosted under their authors' accounts or under the gap-packages organisation (https://github.com/gap-packages/). The latter has the benefit that while the authors will preserve their deciding role on all aspects of the package development, the package will become more visible for potential collaborators and GAP developers may help to set up continuous integration for your package so that every commit to the repository will trigger automated running of package tests and reporting any failures to package maintainers.

#### 76.23 Selecting a license for a GAP Package

As it was mentioned in the description of the `LICENSE` file in Section 76.5, it is advised to make clear in the documentation of the package the basis on which it is being distributed to users. GAP itself is distributed under the GNU Public License version 2 (version 2 or later). We would encourage you to consider the GPL license for your packages, but you might wish to be more restrictive (for instance forbidding redistribution for profit) or less restrictive (allowing your software to be incorporated into commercial software). See Choosing a License for the Distribution of Your Package from https://www.gap-system.org/Packages/Authors/authors.html and also https://choosealicense.com/ for further details.

In the past many GAP packages used the text We adopt the copyright regulations of GAP as detailed in the copyright notice in the GAP manual or a similar statement. We now advise to be more explicit by making the exact reference to the GPL license, for example:

packagename is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. and also including a copy of the full text of the license.

#### 76.24 Releasing a GAP Package

The GAP distribution provides archives in several different formats.

`.tar.gz`

  a standard UNIX `tar` archive, compressed with `gzip`

`.tar.bz2`

  a standard UNIX `tar` archive, compressed with `bzip2`

`.zip`

  an archive in `zip` format, where text files should have UNIX style line breaks

For convenience of possible users it is sensible that you provide an archive of your package in at least one of these formats.

For example, if you wish to supply a `.tar.gz` archive, you may create it with the command

`tar -cvzf packagename-version.tar.gz packagename`

Because the release of the GAP package is independent of the version of GAP, a GAP package should be wrapped up in separate file that can be installed onto any version of GAP. In this way, a package can be upgraded any time without the need to wait for new GAP releases. To ensure this, the package should be archived from the GAP `pkg` directory, that is all files are archived with the path starting at the package's name.

The archive of a GAP package should contain all files necessary for the package to work. In particular there should be a compiled documentation, which includes the `manual.six`, `manual.toc` and `manual.lab` file in the documentation subdirectory which are created by GAPDoc while TeXing the documentation. (The first two files are needed by the GAP help system, and the `manual.lab` file is needed if the main manuals or another package is referring to your package. Use the command `GAPDocManualLab( packagename );` to create this file for your help books if you use GAPDoc.)

Note that wrapping the GAP distribution as a single archive containing the core system and all currently redistributed packages, will change file timestamps, so one should not rely on them anywhere in the package.

For packages hosted on GitHub publishing package release and establishing its website can be very efficiently automated using two tools: ReleaseTools (https://github.com/gap-system/ReleaseTools) and GitHubPagesForGAP (https://github.com/gap-system/GitHubPagesForGAP).

#### 76.25 The homepage of a Package

If you want to distribute your package you should create its homepage containing some basic information, archives for download, the `README` file with installation instructions, and a copy of the package's `PackageInfo.g` file.

The responsibility to maintain this homepage is with the package authors/maintainers.

If you tell the GAP Group about your package (say, by mail to support@gap-system.org) we may consider either

- adding a link to your package homepage from the GAP website (thus, the package will be an undeposited contribution);

- or redistributing the current version of your package as a part of the GAP distribution (this, the package will be deposited), also ;

Please also consider submitting your package to the GAP package refereeing process (see https://www.gap-system.org/Contacts/submit.html for further information).

For packages hosted on GitHub publishing package release and establishing its website can be very efficiently automated using two tools: GitHubPagesForGAP (https://github.com/gap-system/GitHubPagesForGAP) and ReleaseTools (https://github.com/gap-system/ReleaseTools).

#### 76.26 Some things to keep in mind

- Some packages still use for their manuals the old gapmacro format, support for which may be discontinued in the future. We encourage authors of those packages to eventually convert their documentation GAPDoc. New packages are recommended to use GAPDoc, which, for example, is capable of creating HTML documentation with MathJax support, allows easy extraction of examples from documentation for testing, etc. One could also use the AutoDoc which simplifies writing documentation by generating most of the GAPDoc code automatically.

- The concept of an autoloaded package, which existed before GAP 4.5, has been integrated with the needed and suggested mechanism that exists between packages. GAP itself now needs certain packages (for instance GAPDoc) and suggests others (typically the packages that were autoloaded). The decisions which packages GAP should need or suggest are made by developers based on technical criteria. They can be easily overridden by a user using the new `gap.ini` (see 3.2). The default file ensures that all formerly autoloaded packages are still loaded if present.

- Optional `~/.gap` directory for user's customisations which may contain e.g. locally installed packages (see 9.2). If package installation instructions explain how to install the package in a non-standard location, they should mention this.

- Packages loading mechanism allows to make loading packages more informative, while avoiding confusing the user with warning and error messages for packages they didn't know they were loading. For example, many messages are stored but not displayed using the function `LogPackageLoadingMessage` (76.2-6) and there is a function `DisplayPackageLoadingLog` (76.2-6) to show log messages that occur during package loading. Packages are encouraged to use these mechanisms to report problems in loading (e.g. binaries not compiled), rather than printing messages directly.

#### 76.27 Package release checklists

The following checklists should be useful to package authors and maintainers, as well as to everyone involved in the depositing and refereeing of GAP packages.

##### 76.27-1 Checklist for releasing a new package

- Test that the package:

  - does not break `testinstall.g` and `teststandard.g`, and does not slow them down noticeably (see 76.20-4);

  - may be loaded in various configurations (see 76.20-2);

  - follows the guidelines of Section 76.10 about names of functions and variables;

- `PackageInfo.g` file:

  - correctly specifies package version, release date, and package authors;

  - passes validation using `ValidatePackageInfo` (76.3-16);

  - besides mandatory components, which are required to pass validation, also has relevant optional components (such as, for example, URLs of public source code repository and issue tracker; hints to distinguish binary and text files in case of non-standard file names and extensions, etc.);

- Package documentation:

  - is built and included in the package archive together with its source files;

  - states the same version, release date and package authors as specified in the `PackageInfo.g` file;

  - has the same version, release date and package authors details as stated in the `PackageInfo.g` file;

  - is searchable using the GAP help system in all formats (text, HTML and PDF);

  - is clear about the license under which the package is distributed, and refers to the `LICENSE` file which should be included in the package;

- Package archive(s):

  - have correct permissions for all files and directories after their unpacking (755 for directories and executables, if any; 644 for other files);

  - contain files with correct line breaks for the given format (see Section 76.24);

  - contain no hidden system files and directories that are not supposed to be included in the package, e.g. `.gitignore`, `.git` etc.;

- Package availability:

  - not only the package archive(s), but also the `PackageInfo.g` and `README` files are available online;

##### 76.27-2 Checklist for upgrading the package for the next major release of GAP

GAP ecosystem is not static: both the core GAP system and packages redistributed with GAP are in constant development. GAP has a policy that changes that may have a disruptive effect on packages redistributed with GAP should only be introduced in major GAP releases. When the next GAP major release is prepared, a beta version for package authors will be made available in order to give them an opportunity to check and update, if necessary, their packages for the public release of the next major version of GAP.

The following checklist will help you to check how well your package is ready to work with the next major release of GAP

- Check that the package functionality works as expected, package tests run with no discrepancies, and manual examples correspond to new version of GAP. This is a convenient opportunity to polish existing and add new tests, and improve manual examples.

- Revise package dependencies: check that the `PackageInfo.g` file has correct list of needed and suggested packages (see Section 76.11).

- Revise licensing information: check that the package states clearly under which conditions it is distributed and includes a `LICENSING` file with the text of a license (see Section 76.23).

- Rebuild the package documentation to update cross-references to main GAP manuals and, if relevant, to the documentation of other GAP packages. This will ensure that cross-references from the package manual to the main GAP manuals are correct and that the GAP help system will be able to navigate to the more precise location in the package manual. This will also improve the layout of the package documentation by picking up the changes in documenting tools.

- Check if the package still relies on some obsolete variables (see Chapter 77) and replace their usage by the new commands. To perform such check, start GAP with `-O` command line option to disable loading obsoletes, and then load your package.

- Check for any specific advice in release notes for the beta release for package authors.

[Top of Book] [Contents] [Previous Chapter] [Next Chapter]
Goto Chapter: Top 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 Bib Ind

generated by GAPDoc2HTML