1 Getting Started with Packages (original) (raw)
8.15
1 Getting Started with Packages🔗ℹ
There are two ways to manage Racket package installations:
- The package manager graphical interface.
Most users access the package manager graphical interface through DrRacket, which provides a Package Manager... item in the File menu.
You can also install the gui-pkg-manager package, with provides a Racket Package Manager application (which can be launched as racket-package-manager in a command-line environment). - The raco pkg command-line tool.
The raco executable launches various Racket command-line tools, and the raco pkg command groups various package-management sub-commands. The different raco pkgsub-commands are documented in Using raco pkg.
We’ll use the raco pkg command to describe package-management operations here, but the graphical interface allows the same operations.
1.1 What is a Package?🔗ℹ
A package is not something that you refer to directly in your Racket programs. Instead, a package is a set of libraries that fit into the collection hierarchy, and you refer to libraries through their collection-based paths. Libraries that are close in the hierarchy may be provided by different packages, while a single package may provide libraries that are far from each other in the hierarchy (but that are conceptually related, somehow).
Racket documentation tells you which package provides a given library. For example, the documentation for the pict/facelibrary says that it is provided by the pict-libpackage.If you’re reading this in a web browser, clickpict/face to go straight to its documentation.
Over time, packages may be refactored so that a library moves to a different package, but the original package should continue to provide the library, too, by declaring a dependency on the new package. More generally, a package is intended to have an interface that only grows in terms of libraries, bindings, and functionality, which provides a basic level of backward compatibility. Incompatible changes should be implemented in a new package.
1.2 Inspecting Your Installation🔗ℹ
To see the packages that you have installed already, use theraco pkg show subcommand:
raco pkg show
Unless you have an especially minimal Racket installation, you will have packages installed already, probably listed in the “Installation-wide” section. In fact, if you have a typical Racket installation, then raco pkg show will initially show amain-distribution package and a racket-libpackage:
Installation-wide: |
---|
Package Checksum Source |
main-distribution 01..........ef (catalog main-distribution) |
racket-lib fe..........01 (catalog racket-lib) |
User-specific for installation ....: |
[none] |
The “Checksum” column reports the specific implementation of each package that is installed. A package can have a version in a more traditional sense, but the checksum is the “version” as far as the package system is concerned. When you request an update, then a package installation is updated if the current implementation of the package has a different checksum than the installed package, whether or not the package author adjusted the package’sversion.
The “Source” column indicates how each package was installed. Acatalog source indicates that the package was installed by consulting a package catalog. The name after catalog indicates the name of the package as requested from the catalog, which is normally (but not necessarily) the name of the package as it exists in your installation. We discuss other possibilities for “Source” inInstalling Packages.
Neither the main-distribution package nor theracket-lib package actually provides any libraries on its own, but each declares dependencies on other packages. Theracket-lib package depends on native-library packages, if any, for your platform. The main-distribution package depends on lots of packages that have been selected for inclusion in the main Racket distribution. If you provide the --all flag toraco pkg show, then you can see the packages that were automatically installed as a result of installingmain-distribution and racket-lib (or whatever packages you have explicitly selected for your installation).
raco pkg show --all
An asterisk appears beside the name of every package that was “auto-installed” to satisfy a dependency. All auto-installed packages are as available for your use in the same way as explicitly installed packages, but normally your code should refer only to packages that you have explicitly installed. The difference between an auto-installed and an explicitly installed package is how various commands, such as raco pkg show, treat the package. If you specifically request installation of a package that is auto-installed, then the package is promoted and thereafter treated as a explicitly installed package.
1.3 Finding Packages🔗ℹ
The PLT package catalog at
provides a centralized listing of available Racket packages. The PLTpackage catalog normally will be the first place you check when looking for a package.
There are other ways to distribute and reference packages. For example, a package can be installed directly from a ".zip"file—available locally or served from on a web site—or from a Git repository. Such direct references make sense when a package is not yet ready for wide distribution or when it will never be of interest to a wide audience. So, you may find non-catalog references in mailing-list posts, recommended by your friends, or advertised in e-mail spam.
There may be other package catalog services besides PLT’s. Note that even if you discover a package name from PLT’s package catalog, your installation may be configured to consult a differentpackage catalog to locate the package’s implementation (to obtain a pre-built version of the package, for example), but you should expect the installation-configured package catalog to deliver the package that is described on the PLT package catalog.
1.4 Installing Packages🔗ℹ
If you find a package by name from a package catalog, then use the package’s name with raco pkg install:
raco pkg install ‹pkg-name›
If the package depends on other packages that you do not have installed already, then raco pkg install will alert you and ask whether it should install them, too. Use --auto to skip the question and make dependencies installed automatically. Either way, packages installed to satisfy dependencies are marked as auto-installed, which makes them easier to uninstall, and it also makes them hidden by default for raco pkg show (since packages that are installed for dependencies are an implementation detail that you usually do not care about).
The argument that you provide to raco pkg install does not have to be a package name that is recognized by a package catalog. In general, each argument to raco pkg install is apackage source. A package source can refer to a".zip" file, a ".tar" file, a Git repository, a directory-structured web site, or a few other possibilities. In each of those cases, a package name is inferred from thepackage source. After the package is installed, you use the package name with other raco pkg commands to refer to the installed package.
In fact, a package catalog does not actually serve package implementations. It simply maps each package name to apackage source. When the package manager consults apackage catalog, it gets back a package source for the actual package implementation, so each package installed from apackage catalog is actually installed from a ".zip"file, Git repository, etc. Registering with a package catalog is just a way of making your package easier to find and update.
1.5 Updating Packages🔗ℹ
If your package installations become out of date, you can update packages with raco pkg update:
raco pkg update ‹pkg-name›
Either specify individual packages to update, or use --all to update all installed packages for which a new checksum is available.
The way that the package manager finds updates depends on the way that a package was installed. If it was installed by using a package name that was resolved by a package catalog, then thepackage catalog is consulted again to get the currentchecksum for the package, and the package is updated if thechecksum doesn’t match the current installation. If the package was installed directly from a Git reference, then the Git repository is consulted to get the current commit of a particular branch or tag, and the package is updated if the commit identifier doesn’t match thechecksum of the current installation.
In some cases, updating a package may require an update to one of the package’s dependencies. That should happen only when the package requires a new binding, feature, or bug fix from the dependent package, since packages are meant to evolve in an otherwise backward-compatible way. Package versions provide a way for package authors to declare (and for the package manager to check) those dependencies. The end result is that raco pkg update might report a version-mismatch error that forces you to request more package updates than you originally requested.
Normally, you provide package names toraco pkg update. More generally, you can provide a package source to raco pkg update. In that case, a package with the same name must be installed already, and the installed package is replaced with the specified one. Replacing a package with a new package source is a generalization of fetching a replacement package that has a new checksum at a previously specified source.
1.6 Removing Packages🔗ℹ
As you might expect, raco pkg remove removes a package:
raco pkg remove ‹pkg-name›
If the installation of a package triggered auto-installs of other packages, then removing the package does not automatically remove the auto-installed packages. Supply the --auto flag forraco pkg remove, either by itself or when uninstalling packages, to also remove any auto-installed packages that are left without dependents.
The raco pkg remove command will not remove a package if other installed packages depend on it, unless you force the removal. If you want to demote a package from explicitly installed to auto-installed (for clean-up later, perhaps when other packages are removed), then supply the --demote flag to raco pkg remove.
1.7 Creating Packages🔗ℹ
A package normally starts life as a directory containing module files and grows up to become a Git repository that is registered with apackage catalog.
1.7.1 Automatic Creation🔗ℹ
As a convenience, raco pkg new can automate the creation of a single-collection package. To create ‹pkg-name›:
raco pkg new ‹pkg-name›
1.7.2 Manual Creation🔗ℹ
To create a package manually, first make a directory and select its name,‹pkg-name›:
mkdir ‹pkg-name›
Although a package can provide libraries in any number ofcollections, it’s common for a package to provide only libraries in a collection that matches the package name. If that’s the case for your package, then files implementing modules in the‹pkg-name› collection will go directly in the‹pkg-name› directory that you have created.
If your package implements multiple collections, then you’ll need to add a basic "info.rkt" file in the‹pkg-name› directory:
cd ‹pkg-name›
echo "#lang info" > info.rkt
echo "(define collection 'multi)" >> info.rkt
The collection definition tells the package manager that the package implements libraries in multiple collections, and each collection is represented by a sub-directory whose name matches the collection name. Libraries for each collection go in the collection’s directory.
You can start with a single-collection package and later change it to a multi-collection package by restructuring the package directory, so you don’t have to worry much about the choice when you get started.
1.7.3 Linking and Developing New Packages🔗ℹ
Whether creating a single-collection package or amulti-collection package, the next step is to link your development directory as a locally installed package. Useraco pkg install in the ‹pkg-name› directory:
raco pkg install
If you use raco pkg show at this point, you’ll see a line for‹pkg-name›. The “Source” column will show that it’s a linked package, and the “Checksum” column will say #f, which means that there is no checksum. Sub-commands likeraco pkg update will not work on a linked package, because “updates” to the package happen whenever you modify the package’s implementation.
Finally, inside the ‹pkg-name› directory, add directories and/or files to implement the collections and/or modules that your package provides. For example, the developer of atic-tac-toe multi-collection package that providesgames/tic-tac-toe/main and data/matrixlibraries might create directories and files like this:
mkdir -p games/tic-tac-toe
touch games/tic-tac-toe/info.rkt
touch games/tic-tac-toe/main.rkt
mkdir -p data
touch data/matrix.rkt
An "info.rkt" file is not necessary for asingle-collection package with no dependencies, but you may wish to create one, anyway, to hold dependency declarations. Every package at least depends on base, which provides the collections and libraries of a minimal Racket installation. To make your package work best for other users, you will ultimately need to declare all dependencies. (Fortunately, raco setup can check dependencies and help you figure out what dependencies to declare.)
Even for a single-collection package, you may want to create"info.rkt" and include the definition
(define collection "‹pkg-name›")
This definition may seem redundant, since ‹pkg-name› is available as the name of the enclosing directory, but declaring the collection name explicitly prevents the meaning of your package’s implementation from depending on the way that the implementation is referenced.
Finally, in the case of a multi-collection package, note that the "info.rkt" file in ‹pkg-name› is for the package, not for a collection. Definitions such asscribblings or raco-commands work only in a collection’s "info.rkt". For a single-collection package, the "info.rkt" file serves double-duty for the package and collection.
1.8 Sharing Packages🔗ℹ
After your package is ready to deploy, choose either GitHub Deploymentor Manual Deployment, and then go on to Helping Others Discover Your Package.
1.8.1 GitHub Deployment🔗ℹ
First, create a free accounton GitHub, thencreate a repository for your package. After that, your package sourceis:
If you want the package to be at ‹branch› or ‹tag›instead of the default branch, then add "#‹branch›" or"#‹tag›" to the end of the package source. If your package is a subdirectory ‹path› within the repository, add"?path=‹path›" to the end of the package source.
Whenever you
git push
your changes will automatically be discovered by those who useraco pkg update after installing from your GitHub-based package source.
Other Git repository servicesSupport for services other than GitHub requires Racket version 6.1.1.1 or later. can work just as well as GitHub—including GitLab or BitBucket—as long as the server supports either the HTTP(S) protocol or the native Git protocol (but use a git:// path for the latter).
The Racket package manager provides more support for Git-based development than just deployment. See Developing Packages with Git for more information.
1.8.2 Manual Deployment🔗ℹ
Alternatively, you can deploy your package by publishing it on a URL you control. If you do this, it is preferable to create an archive from your package directory first:
raco pkg create ‹package›
Then, upload the archive and its checksum to your site:
scp ‹package›.zip ‹package›.zip.CHECKSUM your-host:public_html/
Your package source is then something like
Whenever you want to provide a new release of a package, recreate and reupload the package archive (and checksum). Your changes will automatically be discovered by those who used your package source when they useraco pkg update.
By default, raco pkg create generates a".zip" archive. For more options, refer to theraco pkg create documentation. If you want to generate an archive through some other means, simply archive what you made in the first part of this section. For more formal details, refer to thepackage definition.
1.8.3 Helping Others Discover Your Package🔗ℹ
By using either GitHub Deployment or Manual Deployment, anyone will be able to install your package by referring to yourpackage source. However, they will not be able to refer to it by a simple name until it is listed on a package catalog.
If you’d like to use the PLT package catalog, browse tohttps://pkgs.racket-lang.org/and upload a new package. You will need to create an account and log in first.
You only need to go to this site once to list your package. The server will periodically check the package source you designate for updates.
If you use this server, and if you use a public Git repository for deployment, then you will never need to open a web browser to update your package for end users. You just need to push to your Git repository, then within 24 hours, the PLT package catalog will notice, and raco pkg update will work on your user’s machines.
1.8.4 Naming and Designing Packages🔗ℹ
We suggest the following conventions for naming and designing packages:
- Packages should not include the name of the author or organization that produces them, but be named based on the content of the package. For example, data-priority-queue is preferred to johns-amazing-queues.
- Packages that provide an interface to a foreign library or service should be named the same as the service. For example,cairo is preferred to Racket-cairo or a similar name.
- Packages should not generally contain version-like elements in their names, initially. Instead, version-like elements should be added when backwards incompatible changes are necessary. For example,data-priority-queue is preferred todata-priority-queue1. Exceptions include packages that present interfaces to external, versioned things, such assqlite3 or libgtk2.
- A version declaration for a package is used only by other package implementors to effectively declare dependencies on provided features. Such declarations allow raco pkg install andraco pkg update to help check dependencies. Declaring and changing a version is optional, and the package catalogignores version declarations; in particular, a package is a candidate for updating when its checksum changes, independent of whether the package’s version changes or even in which direction the version changes. We suggest using a version smaller than "1.0" to indicate that a package’s interface is unstable and changing it to"1.0" when you are ready to commit to backwards compatibility going forward.
- Packages should not combine large sets of utilities libraries with other functionality. For example, a package that contain many extensions to the "racket" collection, like"racket/more-lists.rkt" and"racket/more-bools.rkt"should not also contain complete applications, as other packages interested in the "racket/more-bools.rkt" library will not wish to depend on in such application.
- Packages should normally include both documentation and implementation. To make the implementation of a package available separately from its documentation (for use in environments where local documentation is not useful), define a package‹pkg-name›-lib to hold just the implementation,‹pkg-name›-doc to hold the documentation, and‹pkg-name› that depends on both and that “re-exports” both with an implies declaration (seePackage Metadata). If you want to keep tests separate, put them a‹pkg-name›-test package that is not a dependency of ‹pkg-name›. Similarly, use‹pkg-name›-exe for executables.
- Packages should generally provide one collection with a name similar to the name of the package. For example, libgtk1should provide a collection named "libgtk". Exceptions include extensions to existing collection, such as new data-structures for the "data" collection, DrRacket tools, new games for PLT Games, etc.
1.8.5 Packages Compatible with Racket 5.3.5 and 5.3.6🔗ℹ
A beta version of the package system was added to Racket starting in version 5.3.5. By the time version 6.0 was released, some features were added.
By using only certain older features, it is possible to make a package that can be used with Racket versions 5.3.5, 5.3.6, 6.0, and newer.
In your info.rkt, you should:
- Use #lang setup/infotab (not #lang info).
- Use (define collection 'multi). Even if your package has a single collection, put it in a subdirectory and make a multi-collection package.
- If you depend on a specific version of another package, state this using the (other-package-name required-version)form (not the form with #:version).
Finally, when listing your package onhttps://pkgs.racket-lang.org, you should supply a GitHub source using the URL formatgithub://github.com/‹user›/‹repo›/‹rev›[/‹path›] (not the git:// or http:// format).
1.8.5.1 Version Exceptions🔗ℹ
To make supporting multiple versions of Racket easier, the package catalog software supports version exceptions. Version exceptions allow package authors to specify alternative package sources to be used when installing a given package using a specific version of Racket.
For example, a package that uses on Racket 6.0-specific features could provide a version exception for Racket 5.3.6 using a different branch or tag in the package’s GitHub repository, or a different zip archive, as package source. Users installing the package from Racket 6.0 will use the default source for the package, while those using Racket 5.3.5 will install from the alternative branch, tag, or archive.
For more details, see Package Catalog Protocol.