Skip to content

Commit d8c7c3e

Browse files
committed
fix: warn on C++ extension load failure and add Python 3.14 wheel support
The C++ extension import failure was silently swallowed, causing transport classes to degrade to no-op stubs without any user-visible indication. Emit an ImportWarning with the error details and a macOS-specific hint about libc++ ABI mismatches when Homebrew LLVM is in PATH. Add cp314 to the cibuildwheel build matrix so pre-built wheels are published for Python 3.14 (stable since Oct 2025). Skip free-threaded builds (*t-*) until thread safety is validated. Update CI test matrix and pyproject.toml classifiers accordingly. Add a Troubleshooting section to the README covering the ABI mismatch and silent no-op transport symptoms. Made-with: Cursor
1 parent d5d04b9 commit d8c7c3e

5 files changed

Lines changed: 63 additions & 4 deletions

File tree

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ jobs:
5656
fail-fast: false
5757
matrix:
5858
os: [ubuntu-latest, macos-latest, windows-latest]
59-
python-version: ["3.10", "3.11", "3.12", "3.13"]
59+
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
6060
steps:
6161
- uses: actions/checkout@v6
6262

.github/workflows/wheels.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ jobs:
2828
CIBW_ARCHS_LINUX: x86_64 aarch64
2929
CIBW_ARCHS_MACOS: x86_64 arm64
3030
CIBW_ARCHS_WINDOWS: AMD64
31-
CIBW_BUILD: "cp310-* cp311-* cp312-* cp313-*"
32-
CIBW_SKIP: "*-musllinux*"
31+
CIBW_BUILD: "cp310-* cp311-* cp312-* cp313-* cp314-*"
32+
CIBW_SKIP: "*-musllinux* *t-*"
3333
CIBW_MANYLINUX_X86_64_IMAGE: manylinux2014
3434
CIBW_MANYLINUX_AARCH64_IMAGE: manylinux2014
3535
CIBW_TEST_COMMAND: pytest {project}/tests -v --ignore={project}/tests/integration

README.md

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,52 @@ and type checking.
177177
| `opensomeip.client` | `SomeIpClient` — high-level client composing all components |
178178
| `opensomeip.receiver` | `MessageReceiver` — sync/async message iterator |
179179

180+
## Troubleshooting
181+
182+
### macOS: C++ extension fails to load (`ImportError` / symbol not found)
183+
184+
When installing from source on macOS (e.g. `pip install opensomeip` on a Python
185+
version for which no pre-built wheel is available), the C++ extension may fail to
186+
load at runtime with an error like:
187+
188+
```
189+
ImportError: dlopen(…/_opensomeip.cpython-3xx-darwin.so, 0x0002):
190+
symbol not found in flat namespace '__ZNSt3__113__hash_memoryEPKvm'
191+
```
192+
193+
**Cause:** If [Homebrew LLVM](https://formulae.brew.sh/formula/llvm) is installed
194+
and its `clang++` appears in `PATH` before `/usr/bin/clang++`, CMake will use it
195+
during the build. Homebrew's compiler ships a newer libc++ than the one bundled
196+
with macOS, so the compiled extension references symbols that don't exist in the
197+
system library loaded at runtime.
198+
199+
**Fix — rebuild with the system compiler:**
200+
201+
```bash
202+
CC=/usr/bin/clang CXX=/usr/bin/clang++ \
203+
pip install --no-cache-dir --force-reinstall --no-binary=opensomeip opensomeip
204+
```
205+
206+
**Tip:** Pre-built wheels (available for Python 3.10 – 3.14 on macOS, Linux, and
207+
Windows) are compiled in CI with the correct toolchain and don't have this issue.
208+
If a wheel exists for your platform you'll never hit this problem — it only
209+
occurs when pip falls back to building from the source distribution.
210+
211+
### Silent no-op transport (no socket opened)
212+
213+
If the C++ extension fails to load, the library warns via Python's
214+
`warnings` module and falls back to stub transport classes. These stubs
215+
set `is_running = True` but **do not open any network sockets**. If your
216+
server appears to start but `lsof` shows no listening socket, check for the
217+
`ImportWarning` that opensomeip emits at import time:
218+
219+
```bash
220+
python -W all your_script.py
221+
```
222+
223+
If you see the warning, follow the steps in the section above to fix the
224+
extension build.
225+
180226
## Development
181227

182228
```bash

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ classifiers = [
2121
"Programming Language :: Python :: 3.11",
2222
"Programming Language :: Python :: 3.12",
2323
"Programming Language :: Python :: 3.13",
24+
"Programming Language :: Python :: 3.14",
2425
"Programming Language :: C++",
2526
"Topic :: System :: Networking",
2627
"Topic :: Software Development :: Libraries :: Python Modules",

src/opensomeip/_bridge.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from __future__ import annotations
1212

1313
import functools
14+
import warnings
1415
from typing import TYPE_CHECKING, Any
1516

1617
if TYPE_CHECKING:
@@ -32,8 +33,19 @@ def _load_extension() -> Any:
3233
_ext = _opensomeip
3334
HAS_NATIVE = True
3435
return _ext
35-
except ImportError:
36+
except ImportError as exc:
3637
HAS_NATIVE = False
38+
_msg = (
39+
f"opensomeip C++ extension failed to load: {exc}\n"
40+
"Transport classes will run as no-op stubs (no sockets will be opened).\n"
41+
"On macOS, this is often caused by a libc++ ABI mismatch when building "
42+
"from source with a non-system compiler (e.g. Homebrew LLVM). "
43+
"Rebuild with the system compiler:\n"
44+
" CC=/usr/bin/clang CXX=/usr/bin/clang++ "
45+
"pip install --no-cache-dir --force-reinstall --no-binary=opensomeip opensomeip\n"
46+
"See https://github.com/vtz/opensomeip-python#troubleshooting for details."
47+
)
48+
warnings.warn(_msg, ImportWarning, stacklevel=2)
3749
return None
3850

3951

0 commit comments

Comments
 (0)