Standalone build of htop.
Part of the unpins project — native single-binary builds with no third-party runtime dependencies.
Run the htop program with unpin:
unpin htopTo install it onto your PATH:
unpin install htopnix build github:unpins/htop
./result/bin/htopOr run directly:
nix run github:unpins/htopThe first invocation will offer to add the unpins.cachix.org substituter so most pulls come pre-built.
htop.1 is embedded in the binary — read with unpin man htop.
The Releases page has standalone binaries for manual download.
- Windows is not supported. htop has per-OS process backends (Linux
/proc, macOS Mach, several BSDs) but no Windows backend upstream. Cosmopolitan would only paper over that, not provide one — so we ship Linux + macOS only. See Future: Windows port below. - Embedded terminfo fallback. A curated set of terminfo entries (
xterm-256color,screen-256color,tmux-256color,linux,vt100, …) is baked into the linkedlibtinfo.a, so htop renders correctly on hosts with no/usr/share/terminfo(scratch containers, minimal Alpine, busybox-init systems). When the host has terminfo, the system entry still wins. - libcap Go bindings disabled via
GOLANG=no. They buildgoapps/web,goapps/setid,goapps/gowns— separate helper binaries that htop doesn't use. Skipping them keeps the build closure smaller; the C side of libcap (libcap.a,libpsx.a) is unaffected. - lm_sensors
sensors-detectscript removed. It's a Perl script that pulls perl + bash into the closure. htop only consumeslibsensors.a, never the script, so we drop both the propagated deps and the script itself. - No upstream features are disabled beyond the items above.
Not on the v1 roadmap, but tractable for someone with NT API experience.
Scope. htop's process backend is platform-pluggable — linux/, darwin/, freebsd/, openbsd/, dragonflybsd/, solaris/, pcp/ each sit under htop/<os>/ and the configure script selects one at build time. A Windows backend would slot in as htop/windows/, mirroring the Solaris port in scope (the leanest existing one).
Estimated effort. ~2500–3500 lines of new C inside htop/windows/ plus ~200–400 lines of patches to portable code, broken down roughly:
WindowsProcessList.c(~600–800) —NtQuerySystemInformation(SystemProcessInformation)loop, parse the chainedSYSTEM_PROCESS_INFORMATIONbuffer, populate Process structs in one snapshot per refresh.WindowsProcess.c(~400–500) —Processsubclass with Windows-specific fields (handle count, session ID, integrity level, signing status).WindowsMachine.c(~300–400) — system-wide stats:SystemProcessorPerformanceInformationper core,GlobalMemoryStatusEx,GetTickCount64. Load average doesn't exist on Windows — either omit or fake from CPU run-queue depth.Platform.c(~400–500) — signal table maps toTerminateProcess(Windows has no real signals), nice maps toSetPriorityClass, battery viaGetSystemPowerStatus.UsersTable.c(~80–150) — SID → username cache viaLookupAccountSidW(uncached: one RPC per process per refresh; cache is mandatory).- Headers, meter overrides, build glue (~700–1000) — struct defs the MinGW SDK doesn't expose,
configure.achost detection branch,Platform.hdispatch,Makefile.amwindows_*_la_SOURCES.
Cost drivers beyond LOC.
- NT vs Win32 API tradeoff.
NtQuerySystemInformationis the only sensible way to get all processes + threads + counters per refresh; calling Win32 (EnumProcesses+OpenProcess× N +GetProcessTimes× N + …) multiplies syscalls and won't sustain 1 Hz with 500+ processes. NT API is undocumented but stable since NT 4.0 — Process Explorer relies on it. - PEB walking to read each process's command line:
NtQueryInformationProcess(ProcessBasicInformation)→ PEB pointer →ReadProcessMemoryon theUNICODE_STRING.Buffer. Races with process exit, fails on elevated targets withoutSE_DEBUG_NAME. - UTF-16 boundary. Every Win32 W-suffix API call needs
wchar_t*⇄char*conversion. Roughly 80–100 LOC of conversion plumbing if built under cosmocc (which providestprecode16to8/tprecode8to16), or 120–150 LOC under raw mingw (WideCharToMultiBytewith six parameters and ACP fallback handling). The structural cost — every Win32 surface needs a boundary — is the same with either toolchain. - htop core's locale-naive text handling. Column truncation, incremental search, and width calculation in
htop/Column.c,htop/IncSet.c, etc. truncate by byte count and search viastrstr. The bugs already exist on Linux for Cyrillic/CJK process names, just less visible. A Windows port surfaces them because the typical Windows process name set has more non-ASCII (Гостевой пользователь, Microsoft Windows kanji service names, etc.). Fixing properly is a ~200–400 LOC refactor towardwcswidth-aware truncation in portable code. - Features that don't translate. cgroups column, namespace IDs, CAP_* capabilities, per-pid IO bytes (Windows reports operations, not bytes) — each needs
#ifdefin the UI or a stub.
Toolchain choice (mingw vs cosmocc).
- mingw cross produces a separate
.exe, ~120–200 KB stripped, fits the current htop build structure (configureselects one backend). Most natural; gives 3 binaries total (Linux + macOS + Windows). - cosmocc would let one APE binary run on Linux + macOS + Windows, but only if the build is also refactored to dispatch backends at runtime via
IsLinux()/IsXnu()/IsWindows(). htop'sconfigure-time backend selection bakes inHAVE_LINUX_*macros throughout — that refactor is the dominant cost, not the Windows backend itself. Worth it only if a single-binary-per-package guarantee is more valuable than ~440 KB extra and a per-syscall dispatch layer.
Upstream-ability. htop has accepted platform ports from contributors before (Solaris 2014, FreeBSD 2016, DragonFlyBSD 2018). A clean Windows port has a real chance of merging into htop-dev/htop master, especially if it ships as htop/windows/ with no churn to existing backends. Review will cost an additional 1–2 weeks negotiating portable-code refactors.
Realistic calendar. 2–3 weeks full-time for an engineer fluent in both htop internals and the NT API; 6–10 weeks otherwise (most of which goes to winternl.h and Process Explorer source). Out of scope for v1; tracked as a v2+ stretch goal. Contributions welcome — open an issue first to align on the toolchain choice above.