Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 64676624e6 | |||
| 7604e18587 |
@@ -92,6 +92,22 @@ OS specifics are spelled out per step and in *Platform notes* below.
|
||||
On **ARM64 (aarch64)** there are no pyamg wheels —
|
||||
`requirements.txt` skips pyamg there and the solver falls back to
|
||||
Jacobi-CG: same results, noticeably slower on large grids.
|
||||
**NixOS**: pip's Linux wheels link against standard FHS library
|
||||
paths, which NixOS does not provide — PySide6 fails with
|
||||
`libgthread-2.0.so.0: cannot open shared object file`. The plugin
|
||||
cannot fix this from inside its venv (KiCad installs wheels only);
|
||||
run KiCad inside an FHS environment. `steam-run kicad` alone is
|
||||
**not** enough: its runtime predates Qt 6.5's hard requirement for
|
||||
`libxcb-cursor0`, so Qt aborts with *"no Qt platform plugin could
|
||||
be initialized"*. Supply that one library on top:
|
||||
```sh
|
||||
XCBCUR=$(nix build --no-link --print-out-paths nixpkgs#xcb-util-cursor)
|
||||
QT_QPA_PLATFORM=xcb LD_LIBRARY_PATH=$XCBCUR/lib steam-run kicad
|
||||
```
|
||||
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
|
||||
|
||||
|
||||
+17
-2
@@ -39,9 +39,24 @@ def _fail(message: str, outdir) -> None:
|
||||
def main() -> None:
|
||||
outdir = None
|
||||
try:
|
||||
from kipy.errors import ApiError
|
||||
try:
|
||||
from kipy.errors import ApiError
|
||||
|
||||
from . import board_io, dialog
|
||||
from . import board_io, dialog
|
||||
except ImportError as e:
|
||||
if "cannot open shared object file" not in str(e):
|
||||
raise
|
||||
# pip's Linux wheels link against FHS system libraries;
|
||||
# on NixOS those paths don't exist and PySide6/pynng die
|
||||
# exactly like this. Nothing inside the venv can fix it.
|
||||
raise UserFacingError(
|
||||
f"A compiled dependency cannot load its system "
|
||||
f"libraries: {e}\nThe plugin venv is built from pip "
|
||||
f"wheels, which expect standard (FHS) library paths. "
|
||||
f"On NixOS, run KiCad inside an FHS environment (e.g. "
|
||||
f"steam-run) or enable programs.nix-ld with Qt's "
|
||||
f"runtime libraries - see README, Platform notes."
|
||||
)
|
||||
try:
|
||||
kicad, board = board_io.connect()
|
||||
stackup = board_io.get_stackup_info(board)
|
||||
|
||||
@@ -24,10 +24,16 @@ def _pick_backend():
|
||||
dependency and the selection dialog / progress window put a Qt event
|
||||
loop in this process, after which matplotlib refuses TkAgg
|
||||
("Cannot load backend 'TkAgg' ... as 'qt' is currently running") -
|
||||
exactly what happened on macOS, whose bundled Python ships tkinter."""
|
||||
exactly what happened on macOS, whose bundled Python ships tkinter.
|
||||
|
||||
The probe must import the binding's native core, not just the
|
||||
package: on NixOS `import PySide6` succeeds (pure __init__) while
|
||||
QtCore's .so cannot find the system libraries pip wheels expect
|
||||
("libgthread-2.0.so.0: cannot open shared object file") - promising
|
||||
QtAgg then kills even the error figure at switch_backend time."""
|
||||
for qt in ("PySide6", "PyQt6", "PyQt5", "PySide2"):
|
||||
try:
|
||||
__import__(qt)
|
||||
__import__(qt + ".QtCore")
|
||||
return "QtAgg" if qt in ("PySide6", "PyQt6") else "Qt5Agg"
|
||||
except Exception:
|
||||
continue
|
||||
|
||||
@@ -20,6 +20,25 @@ def test_backend_prefers_qt_over_tk():
|
||||
assert plots._pick_backend() in ("QtAgg", "Qt5Agg")
|
||||
|
||||
|
||||
def test_backend_probe_requires_working_qtcore(monkeypatch):
|
||||
# NixOS: `import PySide6` succeeds (a pure-Python __init__) while
|
||||
# QtCore's .so cannot load the FHS system libraries pip wheels
|
||||
# expect. The probe must import the native core and fall through -
|
||||
# promising QtAgg kills even the error figure at switch_backend
|
||||
# time, and the failure report with it.
|
||||
import builtins
|
||||
real_import = builtins.__import__
|
||||
|
||||
def broken_qt(name, *args, **kwargs):
|
||||
if name.split(".")[0] in ("PySide6", "PyQt6", "PyQt5", "PySide2"):
|
||||
raise ImportError("libgthread-2.0.so.0: cannot open shared "
|
||||
"object file: No such file or directory")
|
||||
return real_import(name, *args, **kwargs)
|
||||
|
||||
monkeypatch.setattr(builtins, "__import__", broken_qt)
|
||||
assert plots._pick_backend() in ("TkAgg", None)
|
||||
|
||||
|
||||
def test_output_dir_falls_back_when_board_dir_unwritable(
|
||||
tmp_path, monkeypatch, capsys):
|
||||
board_dir = tmp_path / "board"
|
||||
|
||||
Reference in New Issue
Block a user