T2 SDE is not just a regular Linux distribution - it is a flexible Open Source System Development Environment or "meta distribution". T2 allows the creation of custom distributions with state of the art technology, up-to-date packages and integrated support for cross compilation. Currently the Linux kernel is usually used, but we also started to port T2 to support compiling home-brew like add-on packages on macOS, BSDs, classic Unix systems (Irix, ...) or support bootstrapping alternative micro kernel systems (like a L4 variant or Fuchsia). Similarly building Haiku, Android, Minix, Hurd, Open (or Pure) Darwin, Haiku and OpenBSD could be supported, too.
It is usually best to start with a pre-built ISO download. More information, including about the latest source tree are at:
"T2" started as a community driven fork of the ROCK Linux project in 2004, aiming for a simple, clean, lightweight and cross-compiling build system.
"T2" was an intern project name for "try two / second try" or "technology two". The idea was to eventually choose a more public relation aware name, but somehow we just kept sticking with t2 so far ;-)
Quick reference for T2 SDE development, system maintenance and hacking. Run commands from /usr/src/t2-src.
Reference docs:
T2 SDE started as a fork of ROCK Linux, and some of the tools date back
to that time. Source build scripts live in scripts/*; binary package handling
is a separate, older layer:
| Tool | Origin | Role |
|---|---|---|
t2 |
added 2023 | modern CLI wrapper around scripts/* |
scripts/* |
ROCK era | the build system itself: Build-Pkg builds one package, Emerge-Pkg resolves dependencies, Build-Target builds whole systems |
mine |
ROCK Linux | the original binary package manager; installs, removes and creates .gem packages, also handles tar.* |
bize |
T2 | lighter reimplementation; installs and removes tar.* binary packages |
Source builds always go through the top-level t2 mapping to internal scripts/*.
Binary package install/remove goes through mine or bize; the stone installer
and t2 uninstall use mine when available and fall back to bize. The
.gem format is the ROCK/T2 binary package container (unrelated to Ruby
gems); plain tar.* packages carry the same content without the wrapper.
- Background: t2, mine and bize
- t2 Command Overview
- Getting Started
- Package Maintenance
- Package Development
- Hacking the Source Tree
- Building Systems
| Command | Does |
|---|---|
t2 up (pull, sync) |
update the source tree (svn/git) |
t2 config |
create/edit a target configuration profile |
t2 install (inst) |
build + install a package and its dependencies |
t2 uninstall <pkg> |
remove a package (via mine/bize) |
t2 upgrade |
upgrade all installed packages (Emerge-Pkg -system) |
t2 build-target |
build a whole target sandbox |
t2 create-iso |
create an ISO after a target build |
t2 download (dl) |
download a package's source assets |
t2 clean (clear) |
clean up build artifacts |
t2 find <keyword> |
find packages by name/metadata |
t2 create <url> |
create a new package from an external URL |
t2 update <pkg> |
bump a package's version metadata |
t2 list-errors |
list build errors across the target |
t2 commit (ci) |
commit changes to the T2 source tree |
t2 apply <patch> |
apply a patch to the tree |
t2 bench |
benchmark the system |
t2 help <cmd> |
help for a sub-command |
Always update the source tree before starting work to avoid working on stale files.
t2 upNote:
t2 update <package>is different: it bumps a package's version metadata (queries Repology, refreshes checksums). It does not update the source tree.
Build (and install) a package and its dependencies. Use -optional-deps=no to
skip optional deps and -parallel 1 for serialized, readable output.
t2 install -optional-deps=no -parallel 1 <package>Rebuild and reinstall a package even if it is already installed and up to
date. Use this after editing a .desc so the change takes effect.
t2 install -force <package>
t2 install -force -optional-deps=no -parallel 1 <package>The second form skips optional dependencies and prints serialized, readable output.
Remove build artifacts (temporary src.* build dirs, logs) to start fresh.
t2 clean <package>
t2 cleanWhen a build fails, T2 writes per-package logs to /var/adm/logs/, named
<stage>-<package>.{out,log,err}. A .err file means that package failed;
.out holds the full output and .log a successful build. The path is:
/var/adm/logs/<stage>-<package>.errList or browse current build errors across the target with:
t2 list-errorsInspect a specific failure directly (full output and the error log):
ls /var/adm/logs/*.err
less /var/adm/logs/9-<package>.err
less /var/adm/logs/9-<package>.outt2 create generates a new package skeleton. For GitHub/GitLab URLs it
queries the API and fills in description, author, license, latest release
version and the [D] download automatically; kde.org and gnome.org URLs
get matching repository defaults.
t2 create https://github.com/<user>/<repo>
t2 create package/<repository>/<name> <tarball-url>It creates package/<repository>/<name>/<name>.desc, adds the copyright
header, runs svn add, then immediately starts a test build. Fill in any
fields it prints as TODOs afterwards.
| Field | Required | Notes |
|---|---|---|
[COPY] |
yes | always GPL-2.0, license of the .desc file itself, not the package |
[I] |
yes | one-line title |
[T] |
yes | description, one sentence per line |
[A] |
yes | upstream author(s) |
[M] |
yes | maintainer name and email |
[U] |
yes | homepage URL |
[C] |
yes | category from misc/share/PKG-CATEGORIES |
[F] |
no | build flags, see below |
[L] |
yes | license from misc/share/REGISTER, e.g. GPL, GPL3, MIT, OpenSource |
[V] |
yes | upstream version |
[P] |
no | build-by-default flag, stage mask and build priority, see below |
[E] |
no | dependencies: add pkg, opt pkg, del pkg |
[D] |
yes | <checksum> <filename> <base-url> |
[P] syntax, e.g. X 01---5---9 110.900:
XorO: build by default or not- 10-character stage mask, one position per stage 0-9: a digit means the
package builds in that stage (0 = host toolchain, 1-2 = cross, 5+ = native),
-means it is skipped there - priority number: a plain sort key for the build order (
sort -k3inscripts/Create-PkgList), the dot is only a naming convention: digits before it are the coarse group (000 dirtree, 101 libc, 102 toolchain, 110 libraries, 5xx applications, 800 kernel), digits after it order packages within the group
Common [F] flags:
| Flag | Meaning |
|---|---|
CROSS |
can be built during the cross-compilation stage |
NO-LTO |
disable Link Time Optimization |
NO-SSP |
disable stack smashing protector |
OBJDIR |
build out-of-tree (separate build directory) |
t2 update bumps a package's [V] version and refreshes the [D]
checksums:
| Invocation | Effect |
|---|---|
t2 update <pkg> |
query Repology for the latest version and update to it |
t2 update <pkg> <ver> |
update to the given version |
t2 update <pkg> refresh |
keep the version, recompute checksums only |
t2 update <url> |
scan a directory listing and update all matching packages |
[D] lines use the legacy "Unix" CRC cksum or, preferably, modern SHA of the decompressed tarball, not of the file:
cripts/Create-CkSumPatch <pkg>
Lint a package's .desc format, and check upstream for newer versions:
scripts/Check-PkgFormat <package>
scripts/Check-PkgVersion <package>Both also accept -repository <name> to sweep a whole repository.
Include the build cache so reviewers have dependency information:
t2 ci --cache <package>By default t2 download uses the T2 mirror, which hides broken [D] URLs. To test the real upstream URL, turn the mirror off, re-fetch, then restore it:
t2 download --mirror none<package>
rm download/Mirror-CacheShow which files have changed across the tree, or scoped to a package:
svn status
svn status package/base/bashFor a per-file line-count summary (+/-), pipe through diffstat:
svn diff | diffstat
svn diff package/base/bash | diffstatShow what changed on the server since your last update (ignores your local edits):
svn diff -r BASE:HEAD | diffstat
svn diff -r BASE:HEAD | colordiff | less -RShow how your working copy differs from the latest upstream HEAD (local + upstream changes combined):
svn diff -r HEAD | diffstatQuick reference:
| Command | Compares |
|---|---|
svn diff |
working copy vs BASE (your last update) |
svn diff -r HEAD |
working copy vs HEAD (latest on server) |
svn diff -r BASE:HEAD |
BASE vs HEAD (server changes only, no local edits) |
Diff one file against upstream (server changes only):
svn diff -r BASE:HEAD package/base/bash/bash.descPull (update) one file from upstream without touching anything else:
svn update package/base/bash/bash.descPipe through colordiff and page with -R to preserve colors:
svn diff | colordiff | less -R
svn diff package/base/bash | colordiff | less -RGenerate a patch to ship upstream. In an svn checkout, svn diff is enough:
svn diff package/<cat>/<package>/<package>.desc > package-fix.patchApply a patch to the tree:
t2 apply <patch-file>For an interactive diff-review + auto-generated cksum and commit log before committing to SVN:
t2 commit bashTo batch commit all locally modified packages that have a [D] download entry:
t2 ci $(grep 'D] .[^ ]' $(svn st package/ | grep '\.desc$' | sed 's/.* //') | cut -d / -f 3)Build a complete system from source into a sandbox under build/<ID>/.
Each config lives in config/<name>/ and is independent of default.
t2 config -cfg miniKey options in the menu:
| Option | Where | Recommended |
|---|---|---|
| Package preselection template | first option (generic target) | Bootstrap or Base |
| Show expert and experimental options | main menu | needed for custom package selection |
| Custom package selection | expert → - Additional Package Selection |
only for fine-tuning |
Templates live in target/generic/pkgsel/*.in and compose via include:
| Template | ~Packages | Contents |
|---|---|---|
| Toolchain | 8 | bare cross toolchain |
| Bootstrap | 99 | smallest self-hosting system (can rebuild itself) |
| Base | 187 | bootstrap + compression, filesystem and network basics |
| Base-xorg / Base-desktop / Base-wayland | more | graphical stacks on top of Base |
The template is re-applied each time Config saves, so switching templates resets the selection.
Enable Custom package selection (SDECFG_PKGSEL), then edit the rules file
(also editable in-menu under Edit package selection rules). Re-run Config
to apply the rules:
$EDITOR config/mini/pkgsel
t2 config -cfg miniRule syntax (one rule per line, patterns may be repo/*):
| Rule | Effect |
|---|---|
O * |
deselect everything |
X base/* |
select the whole base repository |
X dropbear |
select one package |
- somepkg |
remove a package entirely |
= glibc |
reset a package to its default state |
Note: keep the file to plain rule lines: comment-only or blank lines trigger a syntax popup in Config.
Verify the selection before building (X = will build):
grep -c '^X' config/mini/packages
grep '^X' config/mini/packages | awk '{print $4"/"$5}' | lessSources are downloaded per package as needed; pre-fetching with
t2 download -required avoids mid-build network stalls.
t2 download -cfg mini -required
t2 build-target -cfg miniNote: options like
-cfgmust come before mode flags like-required;t2 downloadstops option parsing at the first unknown token and silently ignores the rest.
t2 build-target is equivalent to scripts/Build-Target. Stage order:
0 (toolchain on host), 1-2 (cross into sandbox), then native chroot stages.
Re-running after a failure resumes; already-built packages are skipped.
Per-package logs are written inside the build sandbox; a .err file means
that package failed.
ls build/mini-*/var/adm/logs/ | tail
ls build/mini-*/var/adm/logs/*.errThe finished system root is build/<ID>/.
The kernel .config for a target build is assembled automatically in
layers; later stages override earlier ones:
| Stage | Source |
|---|---|
| 1 | architecture/<arch>/linux.conf{,.sh,.m4} base template |
| 2 | everything enabled as modules (make no2modconfig) |
| 3 | target/<target>/linux.conf.sh script hooks |
| 4 | config/<cfg>/linux.cfg, then target/<target>/linux.conf |
| 5 | make oldconfig validation, modules/nomodules split |
Override options with plain kernel-config lines in
config/<cfg>/linux.cfg. The file is merged automatically when it exists
and overrides the auto-generated config. =n is translated to
is not set. The Config menu offers a built-in editor for this file under
Linux Kernel Options → "Apply custom kernel build configuration
settings":
CONFIG_PREEMPT=y
CONFIG_BTRFS_FS=y
CONFIG_SOUND=n
Config style (Config menu → Linux Kernel Options):
| Style | Effect |
|---|---|
modules |
auto-config, modular where possible (default) |
nomodules |
auto-config, everything built-in |
none |
skip auto-config, config/<cfg>/linux.cfg is used verbatim as the complete .config |
Rebuild the kernel into the target after changing the config:
rm -f build/mini-*/var/adm/logs/*-linux.{log,err}
t2 build-target -cfg miniNote: prefer override snippets over style
none: a full verbatim.configfreezes you to one kernel version, while snippets survive kernel updates because the base config is regenerated each build.
Create a bootable/install ISO from a finished target build. Output is
<prefix>.iso plus a <prefix>.sha checksum in the T2 top directory.
t2 create-iso mini minit2 create-iso <prefix> <config> is equivalent to scripts/Create-ISO.
Useful options (before the prefix):
| Option | Effect |
|---|---|
-size <MB> |
split across media of the given size |
-source |
include package sources on the ISO |
Write the image to a USB stick:
dd if=mini.iso of=/dev/sdX bs=4M status=progressInstall prebuilt binary packages into a mounted system instead of /.
bize installs and removes tar.* binary packages; -R <root> redirects
everything to the target, including registration in the target's own
/var/adm. This is the same mechanism the stone installer uses.
Prerequisite: make the target build produce binary packages:
| Option | Where | Value |
|---|---|---|
| Binary package format | expert → - Binary package format |
tar.zst |
The build then writes one file per package to build/<ID>/TOOLCHAIN/pkgs/.
Install and remove in a target root:
bize -i -R /mnt/target build/<ID>/TOOLCHAIN/pkgs/<pkg>-[0-9]*.tar.zst
bize -r -R /mnt/target <pkg>Seed a fresh root with a whole build:
for p in build/<ID>/TOOLCHAIN/pkgs/*.tar.zst; do bize -i -R /mnt/target "$p"; doneInspect the target's package database:
ls /mnt/target/var/adm/packagesNote:
bizedoes not resolve dependencies; install runtime deps yourself. Run as root so file ownership is preserved.
Historically we adapted SVN when it was state of the art. Currently we mirror to Git for user's convenience and might switch to it as primary repository in the future.
In 2021 René Rebe's https://exactco.de started a feature bounty program! At the time of writing paying out 10€ for bounty-S, 25€ for bounty-M, 50€ for bounty-L and 100€ for bounty-XL feature requests issues marked so by "rxrbln".
The provided patch or pull request must be reasonably clean code, reproducible (at least mostly) build and work. Successful bounties are paid out thru PayPal or (if preferred, and reasonable for the amount) wire transfer within the EU.
The bounties are meant to give back to the community, inspire next generation open source developers and not to feed automated LLM "AI" clankers. Therefore only real humans are eligible. To limit administrative overhead we can unfortunately not pay fractional work.
If in doubt, best ask before working on a larger bounty.
https://github.com/rxrbln/t2sde/issues?q=is%3Aopen+is%3Aissue+author%3Arxrbln