NixOS works: document the full FHS recipe, drop the nix-ld dead end
Build PCM package / build (push) Successful in 5s
Build PCM package / build (push) Successful in 5s
First successful Linux field test (NixOS 26.05, Plasma 6, KiCad 10). Getting there peeled three layers the error messages misattribute: the FHS env itself (libgthread), then libs the xcb-cursor hint hides (the xcb-util family, and libzstd for libQt6Core - in zstd.out, not zstd's default output), and finally Plasma's QT_PLUGIN_PATH feeding the system Qt's platform plugins to the wheel's bundled Qt, a private-ABI mismatch that fails exactly like a missing library. New docs/NIXOS.md carries the verified buildFHSEnv wrapper, the steam-run quick test (now with env -u QT_PLUGIN_PATH), and a guide for chasing future missing sonames. README upgrades Linux from untested to works and links the doc. The in-plugin error no longer suggests programs.nix-ld: the venv python is a Nix binary, so the nix-ld shim never engages for it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -31,13 +31,13 @@ SWIG API. Requires KiCad **10.0.1+**.
|
|||||||
## Setup (one-time)
|
## Setup (one-time)
|
||||||
|
|
||||||
The plugin is developed and tested on **Windows**; **macOS works**
|
The plugin is developed and tested on **Windows**; **macOS works**
|
||||||
(field-tested on KiCad 10 after a round of mac-specific fixes).
|
(field-tested on KiCad 10 after a round of mac-specific fixes), and
|
||||||
**Linux is expected to work but is untested so far** — the code and
|
**Linux works** (field-tested on NixOS — the hardest Linux to run pip
|
||||||
the dependency stack have been audited (KiCad builds the plugin a
|
wheels on; mainstream FHS distributions should be no harder, reports
|
||||||
private Python venv from `requirements.txt` on every platform, from
|
welcome). KiCad builds the plugin a private Python venv from
|
||||||
pre-built wheels only, no compiler needed), but nobody has run the
|
`requirements.txt` on every platform, from pre-built wheels only, no
|
||||||
plugin there yet. Reports welcome! Steps 1–4 are the same everywhere;
|
compiler needed. Steps 1–4 are the same everywhere; OS specifics are
|
||||||
OS specifics are spelled out per step and in *Platform notes* below.
|
spelled out per step and in *Platform notes* below.
|
||||||
|
|
||||||
1. **Enable the API server**: KiCad → Preferences → Plugins → check
|
1. **Enable the API server**: KiCad → Preferences → Plugins → check
|
||||||
*Enable KiCad API*.
|
*Enable KiCad API*.
|
||||||
@@ -87,27 +87,23 @@ OS specifics are spelled out per step and in *Platform notes* below.
|
|||||||
Plot and dialog windows may open **behind** the KiCad window (they
|
Plot and dialog windows may open **behind** the KiCad window (they
|
||||||
are raised best-effort) — check the Dock if nothing seems to appear
|
are raised best-effort) — check the Dock if nothing seems to appear
|
||||||
after a solve.
|
after a solve.
|
||||||
- **Linux** — **untested** (audited only, same caveat). The venv uses
|
- **Linux** — **works** (field-tested on NixOS, KiCad 10; mainstream
|
||||||
|
distributions are audited but not yet field-tested). The venv uses
|
||||||
the system Python (3.9+), so the stack matches your distribution.
|
the system Python (3.9+), so the stack matches your distribution.
|
||||||
On **ARM64 (aarch64)** there are no pyamg wheels —
|
On **ARM64 (aarch64)** there are no pyamg wheels —
|
||||||
`requirements.txt` skips pyamg there and the solver falls back to
|
`requirements.txt` skips pyamg there and the solver falls back to
|
||||||
Jacobi-CG: same results, noticeably slower on large grids.
|
Jacobi-CG: same results, noticeably slower on large grids.
|
||||||
**NixOS**: pip's Linux wheels link against standard FHS library
|
**NixOS**: **works** (field-tested on NixOS 26.05, Plasma 6). pip's
|
||||||
paths, which NixOS does not provide — PySide6 fails with
|
Linux wheels link against standard FHS library paths, which NixOS
|
||||||
`libgthread-2.0.so.0: cannot open shared object file`. The plugin
|
does not provide — PySide6 fails with `libgthread-2.0.so.0: cannot
|
||||||
cannot fix this from inside its venv (KiCad installs wheels only);
|
open shared object file`. The plugin cannot fix this from inside
|
||||||
run KiCad inside an FHS environment. `steam-run kicad` alone is
|
its venv (KiCad installs wheels only); run KiCad inside an FHS
|
||||||
**not** enough: its runtime predates Qt 6.5's hard requirement for
|
environment built with `buildFHSEnv`, and — on KDE Plasma — unset
|
||||||
`libxcb-cursor0`, so Qt aborts with *"no Qt platform plugin could
|
`QT_PLUGIN_PATH`, which otherwise poisons the wheel's bundled Qt
|
||||||
be initialized"*. Supply that one library on top:
|
with the system's Qt plugins. The tested wrapper (exact package
|
||||||
```sh
|
list incl. the non-obvious `zstd.out` and xcb-util family), a
|
||||||
XCBCUR=$(nix build --no-link --print-out-paths nixpkgs#xcb-util-cursor)
|
`steam-run` quick test, and a debugging guide are in
|
||||||
QT_QPA_PLATFORM=xcb LD_LIBRARY_PATH=$XCBCUR/lib steam-run kicad
|
[docs/NIXOS.md](docs/NIXOS.md).
|
||||||
```
|
|
||||||
or build a dedicated FHS wrapper with `buildFHSEnv` whose
|
|
||||||
`targetPkgs` include `kicad`, `xcb-util-cursor`, `glib`,
|
|
||||||
`fontconfig`, `freetype`, `dbus`, `libGL`, `libxkbcommon`,
|
|
||||||
`wayland` and the `xorg` X11/xcb libraries.
|
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
|
|||||||
+128
@@ -0,0 +1,128 @@
|
|||||||
|
# Running Fill Resistance on NixOS
|
||||||
|
|
||||||
|
KiCad builds the plugin a private venv from pip wheels
|
||||||
|
(`requirements.txt`). Those Linux wheels — PySide6 in particular —
|
||||||
|
`dlopen` system libraries at standard FHS paths (`/usr/lib`), which
|
||||||
|
NixOS does not provide. Nothing inside the venv can fix that; KiCad
|
||||||
|
must be **launched in an environment that supplies the libraries**.
|
||||||
|
This page gives a verified, declarative setup (field-tested on
|
||||||
|
NixOS 26.05, KiCad 10, Plasma 6 on Wayland) and maps each failure
|
||||||
|
mode to its cause, because the error messages are misleading.
|
||||||
|
|
||||||
|
## The three failure layers
|
||||||
|
|
||||||
|
You will hit these in order; each fix below removes one.
|
||||||
|
|
||||||
|
1. **`libgthread-2.0.so.0: cannot open shared object file`**
|
||||||
|
(shown in the plugin's own error figure) — no FHS environment at
|
||||||
|
all. PySide6's bundled Qt cannot load glib & friends.
|
||||||
|
2. **`qt.qpa.plugin: From 6.5.0, xcb-cursor0 or libxcb-cursor0 is
|
||||||
|
needed…` / `no Qt platform plugin could be initialized`** —
|
||||||
|
FHS present but incomplete. Beyond the obvious `xcb-util-cursor`,
|
||||||
|
the bundled Qt needs the whole **xcb-util family** (`icccm`,
|
||||||
|
`image`, `keysyms`, `render-util`, `util`) and **`libzstd`**
|
||||||
|
(a hard dependency of `libQt6Core`; note that `pkgs.zstd`'s
|
||||||
|
default output ships only the CLI — the library lives in
|
||||||
|
`zstd.out`). Qt prints the xcb-cursor hint for *any* missing
|
||||||
|
dependency of the platform plugin, so don't trust it literally.
|
||||||
|
3. **`Could not load the Qt platform plugin "wayland"/"xcb" in ""
|
||||||
|
even though it was found`** with all libraries present — the
|
||||||
|
desktop session (KDE Plasma does this) exports **`QT_PLUGIN_PATH`**
|
||||||
|
pointing at the system's Qt plugin directories. That variable takes
|
||||||
|
precedence over the wheel's bundled plugins, so the venv's PySide6
|
||||||
|
(its own Qt, e.g. 6.11.1) tries to load platform plugins built
|
||||||
|
against the system Qt (e.g. 6.11.0) — a private-ABI mismatch that
|
||||||
|
fails exactly like a missing library. The fix is to **unset
|
||||||
|
`QT_PLUGIN_PATH`** for KiCad and everything it spawns. KiCad
|
||||||
|
itself is wxWidgets/GTK and does not use the variable.
|
||||||
|
|
||||||
|
## Recommended setup: an FHS wrapper
|
||||||
|
|
||||||
|
Wrap KiCad in `buildFHSEnv` so a plain `kicad` launch carries
|
||||||
|
everything. Home-manager example (`home.nix`); for a system-wide
|
||||||
|
install put the same package in `environment.systemPackages` in
|
||||||
|
`configuration.nix` instead:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{ pkgs, ... }:
|
||||||
|
|
||||||
|
let
|
||||||
|
kicad-fhs = pkgs.buildFHSEnv {
|
||||||
|
name = "kicad";
|
||||||
|
targetPkgs = p: with p; [
|
||||||
|
kicad glib fontconfig freetype dbus libGL libxkbcommon
|
||||||
|
xcb-util-cursor wayland zlib zstd.out
|
||||||
|
xorg.libX11 xorg.libxcb xorg.libXext xorg.libXrender
|
||||||
|
xorg.libSM xorg.libICE xorg.libXrandr xorg.libXi
|
||||||
|
xorg.libXcursor xorg.libXfixes
|
||||||
|
# xcb-util family needed by PySide6's bundled xcb platform plugin
|
||||||
|
xorg.xcbutil xorg.xcbutilwm xorg.xcbutilimage
|
||||||
|
xorg.xcbutilkeysyms xorg.xcbutilrenderutil
|
||||||
|
];
|
||||||
|
# Plasma exports QT_PLUGIN_PATH (system Qt plugin dirs); the venv's
|
||||||
|
# bundled Qt chokes on those mismatched plugins. KiCad is wx/GTK,
|
||||||
|
# so dropping the variable is safe.
|
||||||
|
profile = "unset QT_PLUGIN_PATH";
|
||||||
|
runScript = "kicad";
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
home.packages = [ kicad-fhs /* replaces bare pkgs.kicad */ ];
|
||||||
|
|
||||||
|
# buildFHSEnv ships no .desktop file; restore the menu launcher.
|
||||||
|
xdg.desktopEntries.kicad = {
|
||||||
|
name = "KiCad";
|
||||||
|
exec = "kicad %F";
|
||||||
|
icon = "kicad";
|
||||||
|
categories = [ "Development" "Electronics" ];
|
||||||
|
mimeType = [ "application/x-kicad-project" ];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Rebuild, **fully quit any running KiCad** (a running instance keeps
|
||||||
|
its old environment), relaunch, click the Ω button. A one-line
|
||||||
|
`Could not load the Qt platform plugin "wayland"` warning may remain
|
||||||
|
if the wayland client stack is unhappy — it is harmless; Qt falls
|
||||||
|
back to xcb (XWayland) and the dialog appears.
|
||||||
|
|
||||||
|
## Quick test without a rebuild
|
||||||
|
|
||||||
|
`steam-run` provides a broad FHS that is one library short
|
||||||
|
(`libxcb-cursor`, required by Qt ≥ 6.5) and, on Plasma, still leaks
|
||||||
|
`QT_PLUGIN_PATH`:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
XCBCUR=$(nix build --no-link --print-out-paths nixpkgs#xcb-util-cursor)
|
||||||
|
env -u QT_PLUGIN_PATH QT_QPA_PLATFORM=xcb \
|
||||||
|
LD_LIBRARY_PATH=$XCBCUR/lib steam-run kicad
|
||||||
|
```
|
||||||
|
|
||||||
|
(Fish: `set XCBCUR (nix build --no-link --print-out-paths
|
||||||
|
nixpkgs#xcb-util-cursor)`, then the same `env …` line.)
|
||||||
|
|
||||||
|
## Debugging further failures
|
||||||
|
|
||||||
|
If a new wheel version needs another library, reproduce the plugin's
|
||||||
|
Qt startup *outside* KiCad against the wrapper's library set — the
|
||||||
|
venv survives at
|
||||||
|
`~/.cache/kicad/10.0/python-environments/th.co.b4l.fill-resistance`:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
ROOTFS=$(nix-store -qR "$(readlink -f "$(command -v kicad)")" \
|
||||||
|
| grep fhsenv-rootfs | head -1)
|
||||||
|
env -i HOME=$HOME DISPLAY=$DISPLAY XAUTHORITY=$XAUTHORITY \
|
||||||
|
LD_LIBRARY_PATH=$ROOTFS/usr/lib64 QT_DEBUG_PLUGINS=1 \
|
||||||
|
~/.cache/kicad/10.0/python-environments/th.co.b4l.fill-resistance/bin/python3 \
|
||||||
|
-c 'from PySide6.QtWidgets import QApplication; \
|
||||||
|
print(QApplication([]).platformName())'
|
||||||
|
```
|
||||||
|
|
||||||
|
A missing library shows up as a plain `ImportError: libfoo.so.N:
|
||||||
|
cannot open shared object file` — map the soname to its nixpkgs
|
||||||
|
attribute (`nix-locate libfoo.so.N`, from `nix-index`) and add it to
|
||||||
|
`targetPkgs`. If instead every library loads and only the platform
|
||||||
|
plugin fails, compare the environment of the *running* KiCad
|
||||||
|
(`tr '\0' '\n' < /proc/$(pgrep -x kicad)/environ`) for Qt variables
|
||||||
|
leaking in from the session — `QT_PLUGIN_PATH` above was found
|
||||||
|
exactly this way.
|
||||||
@@ -53,9 +53,9 @@ def main() -> None:
|
|||||||
f"A compiled dependency cannot load its system "
|
f"A compiled dependency cannot load its system "
|
||||||
f"libraries: {e}\nThe plugin venv is built from pip "
|
f"libraries: {e}\nThe plugin venv is built from pip "
|
||||||
f"wheels, which expect standard (FHS) library paths. "
|
f"wheels, which expect standard (FHS) library paths. "
|
||||||
f"On NixOS, run KiCad inside an FHS environment (e.g. "
|
f"On NixOS, run KiCad inside an FHS environment "
|
||||||
f"steam-run) or enable programs.nix-ld with Qt's "
|
f"(buildFHSEnv wrapper, or steam-run for a quick "
|
||||||
f"runtime libraries - see README, Platform notes."
|
f"test) - see docs/NIXOS.md in the plugin repo."
|
||||||
)
|
)
|
||||||
try:
|
try:
|
||||||
kicad, board = board_io.connect()
|
kicad, board = board_io.connect()
|
||||||
|
|||||||
Reference in New Issue
Block a user