python3Packages.tree-sitter-grammars: on darwin only one grammar can be loaded per process (bare `parser` install name)
### Describe the bug
On darwin, every Python binding in `python3Packages.tree-sitter-grammars.*` links against its grammar's shared object using the bare install name `parser` — no path, no `@rpath`, no unique name:
```console
$ otool -L .../tree_sitter_typescript/_binding.cpython-314-darwin.so
parser (compatibility version 0.0.0, current version 0.0.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1345.100.2)
$ otool -L .../tree_sitter_python/_binding.cpython-314-darwin.so
parser (compatibility version 0.0.0, current version 0.0.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1345.100.2)
```
`dyld` resolves and caches that dependency by its leaf name, so the **first** grammar loaded in a process satisfies `parser` for every grammar loaded afterwards. Each subsequent binding then looks for its own symbol inside the wrong library:
```
ImportError: dlopen(.../tree_sitter_typescript/_binding.cpython-314-darwin.so, 0x0002):
Symbol not found: _tree_sitter_typescript
Referenced from: .../python3.14-python-tree-sitter-typescript-0.23.2/.../_binding.cpython-314-darwin.so
Expected in: /nix/store/...-tree-sitter-bash-0.25.1/parser
```
**Only one grammar is usable per process.** Any consumer that parses more than one language gets exactly one working parser and `ImportError` for the rest — `pkgs.graphify` declares 21.
Upstream's PyPI wheels do not have this problem: they link the parser into `_binding.so` rather than shipping a separate `parser` dylib.
### Steps To Reproduce
These packages currently fail to build for an unrelated reason (`pythonMetadataCheckPhase`, filed separately), so reproduction needs that phase overridden first:
```nix
# gram.nix
let pkgs = import <nixpkgs> { }; in
pkgs.python3.withPackages (ps: with ps.tree-sitter-grammars; map
(g: g.overrideAttrs (_: { pythonMetadataCheckPhase = "echo skipped"; }))
[ tree-sitter-bash tree-sitter-typescript ])
```
```console
$ nix-build gram.nix
$ ./result/bin/python -c "import tree_sitter_typescript" # OK on its own
$ ./result/bin/python -c "import tree_sitter_bash, tree_sitter_typescript"
ImportError: dlopen(...): Symbol not found: _tree_sitter_typescript
Expected in: /nix/store/...-tree-sitter-bash-0.25.1/parser
```
Importing either grammar **alone** succeeds. The failure appears only once a second grammar is imported.
Loading all 25 grammars declared by `graphify` 0.9.35 in one process gives **1 success and 24 failures**, the single success being whichever module is imported first.
### Expected behavior
Multiple `tree-sitter-grammars` Python bindings can be imported in the same process.
Two possible directions:
- give each grammar's shared object a unique install name (`@rpath/libtree-sitter-<lang>.dylib` or similar) instead of the bare `parser`;
- or link the parser into `_binding.so` statically, as the upstream PyPI wheels do.
### Additional context
I have only tested `aarch64-darwin`. I have **not** verified whether Linux is affected — the bare-soname collision may resolve differently under ELF, so please treat this as darwin-specific until someone confirms otherwise.
Related build failure in the same package set, filed separately: the `pythonMetadataCheckPhase` pname/distribution-name mismatch.
### Notify maintainers
Not tagging anyone — happy to add maintainers if that is preferred.
### Metadata
```
nix: Determinate Nix 3.17.0 (Nix 2.33.3)
system: aarch64-darwin, macOS 26.3.1
nixpkgs: 1d4e0f865d68 (2026-06-29)
python3: 3.14.6
affected: python3Packages.tree-sitter-grammars.* (25 checked), pkgs.graphify
```
1 条评论