What does build2-package do?
Resolve ROOT
Let HERE be the directory that contains this SKILL.md (absolute path
from the system context).
ROOT is the build2 skill tree. Use the first candidate whose
guides/packaging-guide-summary.md exists:
HERE/../build2(sibling layout: this directory next to abuild2skill, including a copy into a user-level skills directory)HERE/../..(nested layout: this directory under thebuild2skill'sskills/subdirectory)
If neither exists, stop.
All later read_file paths are ${ROOT}/....
This file is the procedure. The packaging guides under ${ROOT}/guides/
and ${ROOT}/HOWTO/ are the source of truth for how each step is done.
Do not invent a layout, a bdep new invocation, a branch name, or a
publish sequence.
External actions require explicit approval
This skill creates a real, publicly visible package and eventually
publishes it. Nothing that becomes visible outside your own local working
tree happens automatically. That covers: creating a repository on GitHub,
any git push (a branch or a tag), transferring or renaming a repository
on GitHub, opening or merging a pull request, running bdep ci, and
running bdep publish.
Running /build2-package (or /build2 package) is not approval for any
of these, and neither is reaching the gate where one of them happens.
Before performing one of them for the first time in this run, stop, state
exactly what is about to happen (the command, and what it makes visible
externally), and wait for the user's explicit go-ahead for that specific
action. Approval for one such action does not carry over to a later one,
ask again each time. Default assumption: none of these happen unless the
user explicitly asks for that step.
Everything else, local commits, branch creation, editing files, local builds and tests, cloning or fetching read-only, proceeds without asking.
Hard rules
These are not optional. Violating any one is a failed run.
- Never write
buildfiles from scratch. Always start frombdep new. Do not use${ROOT}/scripts/new-package.shfor this workflow. - Never touch
mainafter the firstbdep new --type empty,third-partycommit until the publish-time fast-forward merge ofreview. - Never bundle (vendor) dependencies. Unbundle them as
depends. - Never put main
lib{}/exe{}targets in the rootbuildfile. - Never make a library header-only if upstream ships a compiled mode.
- Never skip the source-distribution recipe (
b dist, thenconfigure,update,test,cleanin the unpacked archive). Greenbdep ciis not enough. - Never lower the generated
depends: * build2/depends: * bpkglines. - Never guess an upstream tag, license, or public-header include scheme. If it is not in the tree or in a fetched page, stop and ask.
- One git commit per logical packaging step (or a tightly related group).
A commit whose tree is exactly one
bdep newinvocation uses that command line as the commit message, nothing else. A commit that creates a.orig/.patchoverlay pair for one upstream file usesPatch <filename>: <reason>(optional<details>body for a non-trivial patch) as its message, see packaging-guide-antipatterns.md. - Do not merge
reviewintomain, do notbdep release, and do notbdep publishuntil local tests, installed-case tests, distribution tests, and CI are green. - Every directory-level symlink (not a plain file symlink) needs a
matching
symlink=direntry in that package's own<pkg>/.gitattributes(a new file,bdep new --packagedoes not generate one), in the same commit that adds the symlink. Verify withfind <pkg>/ -type l -exec test -d {} \; -printand cross-check every hit against<pkg>/.gitattributes.gitdoes not record symlink type and always recreates a file symlink on checkout, so skipping this breaks the package on a Windows checkout. - Never leave a comment or README note that narrates the packaging process itself, an earlier approach that did not work, or a mishap along the way. Comments and READMEs reflect only the final state (see packaging-guide-antipatterns.md, "Don't leave diary-style comments or notes").
- Never create a repository, push, transfer or rename a repository on
GitHub, open or merge a pull request, run
bdep ci, or runbdep publishwithout the user's explicit approval for that specific action, given at the time (see "External actions require explicit approval" above). The default is that none of these happen.
Mandatory reads (this turn, before any write)
Read these files in full with read_file before creating a repository,
editing a buildfile, or publishing. Do not skim.
${ROOT}/guides/packaging-guide-summary.md${ROOT}/guides/packaging-guide-testing.md${ROOT}/guides/packaging-guide-antipatterns.md${ROOT}/HOWTO/package-naming.md
Then load on demand from the map at the end of this file. Never substitute memory for a guide that this file names.
Re-verify against the checklist docs as you go
A full packaging stretch (Gates A-K, or a new-version/revision run)
can span far more turns than a single context window holds. Earlier
turns, including the mandatory reads above, may already be summarized
away by the time you reach a later gate. Having read a guide once at
the start does not mean its rules are still in context, do not rely on
conversation memory for them.
Re-open and re-check the current state of the tree against these checklist-style docs at least once per gate, and again right before Gate K (publish-time):
${ROOT}/guides/packaging-guide-antipatterns.md: what not to do (hand-written buildfiles, fixing upstream in the package, changed upstream layout, header-only despite a compiled mode, bundled dependencies, main targets in the root buildfile, an over-broad revision, bad header inclusion, ad hoc patching, diary-style comments or notes).${ROOT}/guides/packaging-guide-review.md: the same checklist a cppget.org reviewer applies. Self-check the tree against it before publish rather than finding out during the actual review.${ROOT}/HOWTO/third-party-private-headers.md: private headers must not reach the install tree.${ROOT}/HOWTO/buildfile-compile-options.md: which compile/link options are local vs exported.${ROOT}/HOWTO/package-naming.md: the naming decisions made at Gate E, a rename discovered late is expensive.${ROOT}/guides/packaging-guide-summary.mdStep 5: every directory symlink in every package has asymlink=direntry in that package's own<pkg>/.gitattributes(Hard rule 11).
If the tree no longer matches one of these, fix it before moving to the next gate rather than carrying the drift forward.
Arguments
$ARGUMENTS is the invocation text after /build2-package (or after
/build2 package). Parse it in order. The first matching rule wins.
| First token | Mode |
|---|---|
| empty / omitted | new if cwd is not already a packaging repo, else continue |
new | initial packaging stretch |
new-version | new upstream version after the first publish |
revision | packaging revision (X.Y.Z+R) |
continue | resume the in-progress stretch in cwd |
| anything else | if it looks like a git URL or owner/repo, treat as new with that upstream. Otherwise ask. |
Remaining tokens: optional <upstream-url> and optional <tag-or-version>.
If either is missing and required for the mode, ask. Do not invent them.
Report the chosen mode to the user before the first write.
Mode: continue
Inspect cwd (and its git history) and resume at the first incomplete gate in the matching mode below. Evidence beats conversation summary.
| Evidence | Resume at |
|---|---|
No .git, or no bdep new --type empty,third-party first commit | new from the start |
First commit exists, no review branch | create review and continue new |
On review, no upstream/ submodule | add upstream |
upstream/ present, no package directory / no bdep new --package | package structure |
| Package scaffold present, tests or CI not green | testing |
Tests green, review not merged to main | publish-time merge |
On main after merge, no vX.Y.Z tag | release then publish |
| Already published, user asked for a new upstream | new-version |
| Already published, user asked for a packaging fix | revision |
If the repo is on main with packaging commits that should have been on
review, stop. That is a process error. Do not rewrite published history.
Ask the user how to recover.
Mode: new (initial stretch)
Follow the checklist in
${ROOT}/guides/packaging-guide-summary.md
and steps 8-10 in
${ROOT}/guides/packaging-guide-testing.md.
The numbered gates below are the ones that must not be skipped or reordered.
Gate A: existing work
Search all four, in this order, and report the hits:
https://cppget.org/?advanced-searchhttps://queue.cppget.orghttps://github.com/build2-packaginghttps://github.com/build2-packaging/WISHLIST
If a repository or published package already exists, stop and ask whether
to join that work (continue / new-version / revision) instead of
starting a duplicate.
Gate B: empty repository and first commit
Stop and get explicit approval before this gate's external actions:
creating the GitHub repository and pushing the initial commit to it. Do
the local scaffold (bdep new, git add, git commit) first if that
helps show what is about to be pushed, but do not create the remote
repository or run git push until the user has said to go ahead.
Create an empty public git repository in the user's personal workspace.
Description: build2 package for <name>. Clone with SSH. No README, no
license, no GitHub-generated files.
bdep new --type empty,third-party
git add .
git commit -m "bdep new --type empty,third-party"
git push -u origin main
Verify before continuing:
git rev-list --max-parents=0 HEADis this commit.git show --stat --format=%s HEADmessage is exactlybdep new --type empty,third-party.- The tree is only files generated by that command.
If any extra file or hand edit is in that commit, reset and redo. The review process depends on this.
Gate C: review branch
git checkout -b review
Stay on review for every later commit in this stretch. Do not
git checkout main. Do not merge. Do not release. Do not publish.
Gate D: upstream submodule
git submodule add https://github.com/<upstream>/<repo>.git upstream
Use https:// only. Checkout the release commit (tag). Commit:
Add upstream submodule, <tag>.
Gate E: names and layout
Read ${ROOT}/HOWTO/package-naming.md again if needed. Decide, and write
the decisions down before generating the package:
- Git repository name: upstream case, no
build2-prefix, no-packagesuffix. project:andproject =: lowercase unless mixed case is the upstream identifier (Qt is the documented exception).- Package
name::libprefix for libraries unless both Debian and upstream make an executable clash impossible. - Split library vs executable into separate packages.
- Public-header include scheme (subdirectory prefix vs filename prefix).
- Combined vs split
include//src/.
Stay as close to upstream layout as possible.
Gate F: pre-seed then bdep new --package
Create the package directory. Symlink only the upstream meta files that
exist (README.md, LICENSE / equivalent, NEWS / CHANGES /
ChangeLog). Commit that alone. Then:
bdep new --package --lang ... --type lib,...,third-party <name>
Iterate by deleting and re-running, not by hand-editing the scaffold, until
the layout matches. The third-party sub-option is required. Commit with
the exact command line as the message.
If the changelog basename is not a recognized name, set changes-file:
by hand later. See ${ROOT}/HOWTO/package-changes-file.md.
Gate G: version, manifest, dependencies
- Version stays
X.Y.Z-a.0.zuntilbdep release --no-open. summary: under 70 characters, no weasel words, no trailing period.- Accompanying
-tests/-examples/-benchmarks: copy the main summary and append(tests)(or the matching kind). Do not rewrite it. See${ROOT}/HOWTO/tests-extra-dependencies.md. license:is SPDX (orother:). See${ROOT}/guides/packaging-license.md.- Uncomment the
pkg.cppget.orgprerequisite. Use the least-stable section that still contains every dependency. Do not leavequeue.cppget.orgin a long-livedrepositories.manifest. bdep sync -aafterdependsedits.- Interface headers in this library's public headers go in
intf_libs. Everything else goes inimpl_libs.
Gate H: fill source and buildfiles
Fill the package tree with upstream source before touching buildfiles:
symlink individual header/source files first, and symlink a whole
subdirectory only when that saves many individual symlinks (requires the
buildfile-in-prefix layout, see packaging-guide-antipatterns.md). Follow
the worked example in
${ROOT}/guides/packaging-guide-summary.md Step 5.
Mandatory: for every directory symlink just added, add a matching
symlink=dir entry to that package's own <pkg>/.gitattributes (create
the file if it does not exist yet) in the same commit. Verify with
find <pkg>/ -type l -exec test -d {} \; -print and cross-check every hit.
This is Hard rule 11, skipping it breaks the package on a Windows checkout.
Commit the symlinks (and .gitattributes) before adjusting buildfiles, so
rollback is easy.
Then adjust generated files only. Preserve generated structure and comments.
Load on demand:
- headers / private headers:
${ROOT}/HOWTO/third-party-private-headers.md - SONAME / output name:
${ROOT}/HOWTO/match-upstream-library-name.md - compile options:
${ROOT}/HOWTO/buildfile-compile-options.md - system libs:
${ROOT}/HOWTO/link-system-library.md - Windows
.rcresources:${ROOT}/HOWTO/windows-resource-file.md - pthread:
${ROOT}/HOWTO/link-pthread.md - feature
require:${ROOT}/HOWTO/require-dependency-feature.md
Verify a throwaway install:
b install config.install.root=/tmp/install
Public headers must land in a library subdirectory (or include the library name in the filename). No private headers in the install tree.
Gate I: tests
A library needs at least one test to be publishable.
- Smoke test under
tests/basics/: include the public header, call at least one non-inline function. - Local:
bdep updateandbdep test -a. - Installed case: the recipe in packaging-guide-testing.md Step 9.
- Source distribution, including
b cleanin the unpacked archive. - Commit on
review. Then stop and get explicit approval beforegit push -u origin reviewand beforebdep ci, these are two separate external actions (a push, and a CI queue submission). Once approved and run, wait until no configuration is<unbuilt>orbuilding. - Only then replace the smoke test with upstream tests (if applicable).
Extra test-only dependencies belong in a sibling
-testspackage.
Unsupported platforms go in builds: / build-include: /
build-exclude:, not as ignored CI red. See
${ROOT}/HOWTO/builds-ci-filtering.md.
Gate J: READMEs
Keep PACKAGE-README.md on the generated template. Fill <...>
placeholders. Do not add sections. Accompanying packages use the short
template in packaging-guide-testing.md, not the Usage-style template.
Adjust repository README.md.
Gate K: publish-time only
Do this only after Gates I and J are green. Every numbered step from 2 onward is an external action and needs its own explicit approval, given right before that step, not assumed from having reached this gate.
- Fast-forward
reviewintomain(git merge --ff-only review). If that fails, stop.mainshould still be the firstbdep newcommit. This step is local, no approval needed. - Stop, get explicit approval, then transfer the repository to
github.com/build2-packagingbefore the first publish (GitHub Settings, Danger Zone, Transfer). Rename first if the name still has abuild2-prefix or-packagesuffix. If you transferred while still onreview, merge through a pull request (base: main,compare: review) becausemainis protected on that org, opening and merging that PR is its own external action and needs its own approval too. - Stop, get explicit approval, then from
main:bdep release --no-open --show-push, review the commit, push the tag. - Stop, get explicit approval, then
bdep publish. Review the queue build. Do not pass--section=stableunless the version would otherwise land in the wrong section (zero major that upstream does not treat as alpha).
After the first submission, the package waits in testing for a
build2-review. That review is a different skill.
Mode: new-version
Read ${ROOT}/guides/packaging-guide-version-management.md in full before
any write. Do not use a branch named review (that name is reserved for
the initial stretch).
git checkout -b wip-X.Y.Zbdep release --open --open-base X.Y.Z- Update
upstream/to the new release tag. Commit that alone. - Mandatory: compare against a fresh scaffold. In a temporary directory
outside the repository, run
bdep new --type empty,third-party <repo>and, inside it, thebdep new --package ... --type <type>,...,third-partycommand you would use today, once per package type (not per package). Diff the real repository against it:manifest,PACKAGE-README.md, repositoryREADME.md,repositories.manifest,.gitattributes,.gitignore,build/*.build, root and sourcebuildfiles,tests/build/*. List every difference that reflects a newer recommendation rather than a deliberate package-specific adjustment. Apply each as its own atomic commit, or report it to the user if out of scope. See${ROOT}/guides/packaging-guide-version-management.md("New version: compare against a freshbdep newscaffold"). - Review the upstream diff (
gitkorgit diff vOLD..vNEWinsideupstream/) for layout, dependencies, source files, and build-system changes. - Re-apply any
.orig/.patchoverlays. Each overlay is its own atomic commit, samePatch <filename>: <reason>format. See antipatterns. - Adjust symlinks and
buildfiles (update.gitattributesfor any new or changed directory symlinks, see Hard rule 11). Reviewmanifestand both READMEs. - Repeat Gate I (local, installed, dist including
clean, CI), the same explicit-approval requirement applies to its push andbdep cistep. - Fast-forward merge
wip-X.Y.Zintomainif you are the maintainer (local, no approval needed), or, with explicit approval, open a PR if you are not. - Stop, get explicit approval, then
bdep release --no-open --show-push, then, with a separate explicit approval,bdep publish.
A from-scratch rewrite of upstream may mean deleting the package directory and repeating Gate F on this branch.
Mode: revision
Read ${ROOT}/guides/packaging-guide-version-management.md (New Revision)
in full.
Allowed changes: bug fixes in buildfiles / manifest / packaging
infrastructure, plus critical upstream bugs backported from upstream.
No exported-target renames, no config-variable renames, no layout
rewrites.
Mandatory: do the fresh-scaffold comparison from Mode: new-version step 4, but apply only differences that stay strictly backwards compatible under the rules above. Report the rest to the user for the next upstream version.
The revision release is one squashed commit (bdep release --revision,
with --amend --squash N if the work was developed as several commits).
Test locally first, then, with explicit approval for the push and
bdep ci, test with CI, and only then, with a separate explicit
approval, bdep publish.
Stop and ask
Stop rather than guess when any of these is true:
- Upstream has no tagged release.
- Public headers use unqualified names like
<util.h>(read antipatterns, "Bad Header Inclusion Practice", before continuing). - A compiled mode does not work on a required platform.
git merge --ff-only reviewfails.- Dist-archive
b cleanfails whilebdep testis green. - The user asked only for a review of an existing submission
(switch to
build2-review).
On-demand map
| Need | File |
|---|---|
| Concepts, review branch, steps 1-7 | ${ROOT}/guides/packaging-guide-summary.md |
| Tests, CI, merge, publish | ${ROOT}/guides/packaging-guide-testing.md |
| What not to do, patching | ${ROOT}/guides/packaging-guide-antipatterns.md |
| New version / revision | ${ROOT}/guides/packaging-guide-version-management.md |
| Repository / project / package names | ${ROOT}/HOWTO/package-naming.md |
| License field | ${ROOT}/guides/packaging-license.md |
| Accompanying test packages | ${ROOT}/HOWTO/tests-extra-dependencies.md |
| Version / constraint syntax | ${ROOT}/guides/bpkg-package-name-version.md |
bdep new layouts | ${ROOT}/bdep/bdep-new-layouts.md |
| Review of the result | ../build2-review/SKILL.md |