Skip to content

Installing from source

Gordon Heydon edited this page Sep 24, 2026 · 3 revisions

Installing a package from source

A release is normally a binary: MVPKG install <name> downloads the pre-built tar and unpacks it, compiling nothing. Sometimes there is no binary to download, or you want the package's own tree to edit. Both build from source, and neither needs the git package.

You usually don't have to ask

If the registry has no binary for your system and machine, MVPKG install builds from source on its own:

MVPKG install mvx-lang/curl-cmd
fetching mvx-lang/curl-cmd 1.2.0 ...

There is nothing to opt into and nothing else to install first. The registry selects the package's source tarball, MVPKG downloads and unpacks it exactly as it would a binary, and then compiles it.

It is recorded as an ordinary install of that version, because that is what it is — the same release, built here instead of on a build machine:

PACKAGE               VERSION       STATUS
mvx-lang/curl-cmd     1.2.0         system

Before mv_package#160 this refused, with "no compatible release for mvx/arm64 — install the git package to build from source", and demanded a package with native libgit2 code before you could install anything at all.

Asking for it: --source

--source gives you the package's own tree in a working copy, and builds from there — for developing the package, or for running a branch.

MVPKG install <name>[@ref] [--source [<dir>]]
MVPKG install mvx-lang/cmd --source
MVPKG install mvx-lang/cmd@dev --source
MVPKG install mvx-lang/cmd --source /u/work/cmd

<dir> is where the tree lands. Left out, it is the package's short name under $HOME — mvx-lang/cmd becomes $HOME/cmd. A relative path resolves under $HOME too, so the copy is somewhere writable rather than wherever the account happens to sit.

@ref is any ref the repository has: a branch, a tag, a commit.

A --source install is recorded as source rather than a version number, which is how MVPKG list and MVPKG update tell it apart:

PACKAGE               VERSION       STATUS
mvx-lang/getopt       source        system

With git, and without it

with the git package without it
where the tree comes from git clone, through the git engine (libgit2, no shell, any tier) a tarball download
no @ref the repository's default branch the registry's source asset for that release
@ref that ref checked out https://github.com/<owner>/<repo>/archive/<ref>.tar.gz
MVPKG update fast-forwards with a pull re-fetch (see below)

git is preferred, not required. A clone has an origin and can be pulled later; a tarball tree cannot, and that is the whole difference.

The tarball route uses .tar.gz rather than GitHub's .zip deliberately: MVPKGOS has an UNTAR op and no unzip, and UNTAR already unwraps the single <repo>-<ref>/ directory an archive arrives in. GitHub serves every ref that way, HEAD included.

Build dependencies

A source install compiles, so whatever it compiles against has to be there first — mvpkg itself supplies the shared PLATFORM.H that managed packages $INCLUDE, for instance. Those are declared apart from runtime dependencies:

{
  "dependencies":    ["mvx-lang/getopt"],
  "devDependencies": ["mvx-lang/mvpkg"]
}

In PKG they are the lines marked +. MVPKG installs them before building, and says so:

installing build dependency mvx-lang/mvpkg ...

Anything already in this account's lock is reported and skipped. A binary install receives an already-compiled package and pulls none of them.

What gets recorded

Where What
store installed the package — its version for an automatic source build, source for --source
store SRC.<key> a --source working copy's path, so MVPKG update can find it
account lock the version or source, and for a clone the ref and the resolved commit SHA

The lock pins the commit rather than the ref on purpose: dev today and dev next week are different trees, so pinning the name would reproduce a name rather than a build. If the SHA cannot be read the pin is left empty — that costs reproducibility, not the package.

Updating

MVPKG update <name>

An automatic source build updates like any other package: a newer release means a newer download, built again.

A --source working copy depends on how it was made. A clone is fast-forwarded with a pull and rebuilt, so pulled — or locally edited — source goes live. A tarball tree has no origin to pull from, and MVPKG says so rather than failing at a pull it could never do:

mvx-lang/cmd: /u/work/cmd is a source tree with no repository (fetched
  as a tarball), so there is nothing to pull.  Re-fetch it with:
  MVPKG install mvx-lang/cmd --source /u/work/cmd

When it cannot work

A package builds from source through the same declarative path a binary install uses — fold native CallC code, catalog, deploy the verbs and files the manifest declares. There is no package-supplied build script, deliberately: a source install runs no code the manifest did not describe.

A package that does not claim your platform is refused outright, before anything is downloaded:

$ MVPKG install mvx-lang/curl-cmd          # on mvx
mvx-lang/curl-cmd: not installed — supports udt, uv, jbase, not mvx

A package that declares no systems at all is not refused — plenty predate the field, and refusing on silence would make a missing field an uninstallable package.

What is left is a package that claims your platform and still will not build. That fails at the compile, naming the item. It is a fact about the package, not about your install — report it to the package.