gmt_update
WARNING: This is a developer tool for updating GMT binaries. It is not yet intended for end users.
Fetch and apply GMT binary updates from a remote manifest.
Synopsis
gmt_update [ manifest_url ] [ --dry-run ] [ --allow-dirty ] [ --root dir ]
gmt_update --show [ manifest_url ] [ --root dir ]
gmt_update --make-manifest [ -o file ] [ --files list ] [ --version str ] [ --root dir ]
gmt_update --help | -h
Description
gmt_update is a small, self-contained C executable shipped alongside the
regular GMT tools in bin/. It exists so that an end user can keep an
installed GMT tree up-to-date with the most recent development binaries without
having to wait for the to the release of a new version, or rebuild from source.
The updater is forward-only and version-gated: it refuses to install an older release on top of a newer one, and it requires an explicit confirmation before touching any local file. It is also restricted to updating only files belonging to the current development cycle, so it will never replace a 6.7 dev file with a 6.6.0, for example. Files locked by a running GMT process are staged on the side and applied on the next invocation, so an update cannot corrupt a session that is currently in use.
A single executable handles three roles, selected by the first argument:
with no subcommand (or just a manifest_url), it performs an update;
with
--show, it prints a per-file diff but does not download anything;with
--make-manifest, it generates the manifest that other installs will later consume. This second role is intended for release engineering.
Channels
Each official interim binary update is published as a set of channels, one per
combination of operating system and processor architecture. The compile-time
channel of an individual gmt_update binary is fixed and printed at the top
of the --help output. The six supported channels are:
Each channel sees only its own manifest. A win_x64 gmt_update will
never download a Linux binary and vice versa.
How the manifest is located
The default manifest_url is the GitHub REST API endpoint for the GMT project’s latest release:
When the updater is given an api.github.com/.../releases/latest URL it
fetches the JSON, walks the assets[] array, and follows the
browser_download_url of the asset whose name is
manifest_<channel>.txt. Every other file listed in that manifest is then
fetched as a sibling of the manifest itself, so a release simply consists of
the manifest plus all referenced binaries uploaded to the same location.
A literal URL pointing directly at a manifest_*.txt is also accepted and
used verbatim; this is what you want when testing against a private mirror.
Note
The updater never constructs a static release-asset URL on its own. This
is a deliberate design choice: GitHub does not provide a stable
latest/<asset> URL, and any attempt to invent one will produce
404 errors as soon as the release name changes. Always go through
the API.
Options
Common options
- manifest_url
URL of the manifest to read. Defaults to the GitHub API endpoint described above. May also be the direct URL of a published
manifest_<channel>.txt(useful for staging tests).- --root dir
Override the install root. By default the updater resolves its own executable path (following symlinks), strips the trailing
bin/component, and uses the resulting directory as the install root. All relative paths in the manifest are interpreted under this root.- --help, -h
Print a compact synopsis to standard output and exit.
Update mode
- --dry-run
Resolve the manifest, fetch and parse it, and print the per-file diff, but do not download or replace anything. No confirmation prompt is shown. This is the safe way to preview an upgrade.
- --allow-dirty
Permit running against a developer build whose version string contains
-dirty(i.e. built from an uncommitted working tree). Without this flag such builds are refused, because the version comparison against the manifest cannot be trusted.
Manifest-generation mode (- -make-manifest)
- -o file
Write the generated manifest to file. When omitted, the manifest is written to
./manifest_<channel>.txtin the current directory — the same basename the consumer side resolves via the GitHub API, so the file can be uploaded to the release as-is.- --files list
A plain-text file with one repository-relative path per line; lines starting with
#and blank lines are ignored. Overrides the built-in list of artefacts for the current OS.- --version str
Use str as the manifest
version:field instead of running<root>/bin/gmt --versionto probe it.- --root dir
Hash files under dir instead of under the updater’s own install root. Useful for packaging a build that lives in a staging directory.
Version gate
Before any download decision, the updater spawns
<install_root>/bin/gmt --version and parses the output to obtain the
local version (for example, 6.7.0_d3435c5_2026.05.19, or
6.7.0_8b76b26-dirty_... on a developer build). It then compares that to
the manifest’s version: field using a (semver, date) tuple:
if the local version is newer than the manifest, the updater refuses to proceed — there is nothing to upgrade to;
if the local version is equal, only individual files whose SHA-256 differs from the manifest will be replaced;
if the manifest is newer, the updater offers to upgrade.
Dirty builds (-dirty in the version string) are rejected unless
--allow-dirty is passed.
Confirmation prompt
After the diff is computed the updater prints a summary of the form
N file(s) will be downloaded and replace local copies under
<install_root>
Proceed? [y/N]
and waits on standard input. Anything other than y (or Y) aborts
cleanly without touching the filesystem.
If any of the stale files turn out to be newer on disk than the manifest’s build timestamp (typically because the user just rebuilt that DLL locally), a second prompt appears
WARNING: K of those files are NEWER on disk than the manifest's
build timestamp (<ISO-8601>).
Replacing them would OVERWRITE local newer copies
(typically a just-rebuilt developer DLL).
Also overwrite the K locally-newer file(s) (DOWNGRADE)? [y/N]
A default-no answer keeps the local copies and tags them KEEP-LOCAL
in the apply phase; the non-regression files still update.
Integrity checks
Each downloaded file is written to a temporary <name>.new sidecar and its
SHA-256 is recomputed before the swap. If the hash does not match the
manifest, the temporary file is discarded and the original is left untouched.
The manifest is the trust anchor and must be served over HTTPS; the
SHA-256 column binds content to identity.
Locked files
If the destination file is held open by another process (most commonly the
gmt.exe you are about to upgrade, or a long-running script that has
loaded libgmt), the swap is deferred:
on Windows,
MoveFileExAwithMOVEFILE_REPLACE_EXISTING | MOVEFILE_DELAY_UNTIL_REBOOTis attempted, and the validated download is also staged next to the target as<file>.pending. The next run ofgmt_updatewill apply that pending file as soon as the lock is gone;on Linux/macOS, the staged
<file>.pendingis renamed into place on the next run.
On Windows the updater additionally calls the Restart Manager API to report which process IDs currently hold each locked file.
Manifest format
The manifest is a plain-text file, one record per line; blank lines and
lines starting with # are ignored. Header records appear once:
version: <gmt-version-string>
build: <ISO-8601 UTC timestamp>
channel: <os>_<arch>
Followed by one file record per updatable artefact:
file <relpath-from-install-root> <size-bytes> <sha256-hex-64chars>
An optional fifth field on a file line is interpreted as a
per-file download URL override, useful when a single file must be served
from a different host. When omitted (the normal case), each file is fetched
as a sibling of the manifest URL itself.
The manifest is terminated by
end
Examples
1. Check what an update would do (no changes made):
gmt_update --dry-run
2. Apply the latest official release:
gmt_update
When run from a default Windows install, this resolves the GitHub API,
locates the manifest_win_x64.txt asset of the latest release, diffs each
listed binary against your installed bin/gmt.exe, bin/gmt_w64.dll
and friends, prompts Proceed? [y/N], and on y downloads and swaps in
just the binaries that have actually changed.
3. Pin to a specific manifest URL (mirror / staging):
gmt_update https://my-mirror.example.com/gmt/6.7.0/manifest_win_x64.txt
4. Inspect the diff verbosely without ever connecting to do an update:
gmt_update --show
This prints a table such as
current bin/gmt.exe 0a1b2c3d4e5f 0a1b2c3d4e5f
STALE bin/gmt_w64.dll deadbeefcafe feedfacecafe yes
summary: 1 stale, 0 missing, 1 pending
5. Update an installation that is not where the updater lives:
gmt_update --root D:\opt\gmt-staging
6. Generate the manifest for a release you just built locally:
cd <release-staging>
gmt_update --make-manifest
The above writes ./manifest_<channel>.txt in the current directory.
Upload that file together with the referenced binaries to the same release
(or the same directory on a private mirror) and the consumer side is done.
7. Generate a manifest from a custom file list and a hand-set version:
gmt_update --make-manifest -o manifest_win_x64.txt --files my_files.txt --version 6.7.0_rc1
with my_files.txt containing, e.g.
# Core binaries
bin/gmt.exe
bin/gmt_w64.dll
bin/postscriptlight_w64.dll
bin/gmt_plugins/supplements_w64.dll
Security notes
The manifest is the only trust anchor. Always serve it over HTTPS. The SHA-256 column binds each binary’s identity to its content; an attacker who can substitute a binary but not the manifest cannot make the updater swap it in.
The updater never executes any downloaded file; it only renames it into place.
The GitHub REST endpoint is reached anonymously; no token is required.