Skip to content

Commit 5d66230

Browse files
robtaylorclaude
andcommitted
Add ngspice shared library support with unified error handling
Implements support for running simulations using the ngspice shared library interface alongside the existing external process (QProcess) execution mode. Key features: - CMake options: WITH_NGSPICE_SHARED and WITH_EXTERNAL_SIMULATORS - NgspiceShared wrapper class for libngspice API integration - Unified SimulatorError enum for type-safe error handling across backends - Conditional compilation supporting three build configurations: 1. Both modes enabled (shared library priority, external fallback) 2. Shared library only (WebAssembly/Emscripten compatible) 3. External process only (traditional QProcess-based) - No breaking changes to existing API Implementation details: - Created qucs/extsimkernels/ngspice_shared.{h,cpp} wrapper - Modified AbstractSpiceKernel to conditionally compile QProcess code - Updated Ngspice class to dispatch to appropriate backend - Added SimulatorError enum with distinct codes for each backend - Shared library errors use negative values, process errors positive - Updated Xyce simulator for conditional QProcess support All three build configurations tested and working on macOS. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 52c991a commit 5d66230

File tree

11 files changed

+1018
-9
lines changed

11 files changed

+1018
-9
lines changed

CLAUDE.md

Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
# CLAUDE.md
2+
3+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4+
5+
## About Qucs-S
6+
7+
Qucs-S is a graphical circuit simulator with support for multiple SPICE simulation kernels (Ngspice, Xyce, SpiceOpus) and the native Qucsator engine. It's a Qt6-based C++ application with extensive component libraries and visualization capabilities.
8+
9+
## Build System
10+
11+
### Building
12+
All builds use CMake with out-of-source builds required:
13+
14+
```bash
15+
git submodule init
16+
git submodule update
17+
mkdir builddir
18+
cd builddir
19+
cmake .. -DCMAKE_INSTALL_PREFIX=/your_install_prefix/
20+
make
21+
make install
22+
```
23+
24+
### Build Options
25+
26+
#### Simulator Backend Configuration
27+
- **`WITH_NGSPICE_SHARED`** (default: OFF) - Enable ngspice shared library support
28+
- When enabled, simulations use ngspice as a shared library (libngspice) instead of external process
29+
- Requires libngspice development package installed
30+
- Example: `cmake .. -DWITH_NGSPICE_SHARED=ON`
31+
- Install on macOS: `brew install libngspice`
32+
- Install on Ubuntu: `sudo apt-get install libngspice0-dev`
33+
34+
- **`WITH_EXTERNAL_SIMULATORS`** (default: ON) - Enable external simulator support (QProcess-based)
35+
- Traditional mode: runs simulators (ngspice, xyce, etc.) as external processes
36+
- Can be disabled if only using shared library mode
37+
- Example: `cmake .. -DWITH_EXTERNAL_SIMULATORS=OFF`
38+
39+
Both options can be enabled simultaneously. Priority order: shared library → external process.
40+
41+
### Dependencies
42+
- **Required**: Qt6 (Core, Gui, Widgets, Svg, SvgWidgets, Xml, PrintSupport, Charts), CMake, flex, bison, gperf, dos2unix, C++20 compiler
43+
- **Runtime**: ngspice (primary simulation kernel, or libngspice if using shared library mode)
44+
- **Optional**: libngspice (for WITH_NGSPICE_SHARED)
45+
46+
### Running
47+
```bash
48+
cd /your_install_prefix/bin
49+
./qucs-s
50+
```
51+
52+
### Testing
53+
Limited test coverage exists:
54+
```bash
55+
cd builddir
56+
ctest
57+
```
58+
59+
Individual test executable: `builddir/qucs/geometry/test_geometry`
60+
61+
## Code Organization
62+
63+
### Main Application (`qucs/`)
64+
- **qucs.cpp/h**: Main application window (QucsApp class)
65+
- **schematic.cpp/h**: Schematic editor canvas and logic
66+
- **main.cpp**: Application entry point
67+
- **mouseactions.cpp**: Mouse interaction handling for schematic editor
68+
69+
### Component System (`qucs/components/`)
70+
Contains 300+ component implementations. Each component typically has:
71+
- `.cpp` file with component logic and properties
72+
- `.h` file with class definition
73+
Components inherit from base Element class
74+
75+
### Simulation Kernels (`qucs/extsimkernels/`)
76+
- **abstractspicekernel.cpp/h**: Base class for SPICE kernel interfaces
77+
- Conditionally compiles QProcess code based on WITH_EXTERNAL_SIMULATORS
78+
- Provides common netlist generation and output parsing
79+
- **ngspice.cpp/h**: Ngspice integration (primary kernel)
80+
- Supports both external process (QProcess) and shared library modes
81+
- Automatically selects mode based on build configuration
82+
- **ngspice_shared.cpp/h**: Ngspice shared library wrapper (when WITH_NGSPICE_SHARED enabled)
83+
- Interfaces with libngspice via C API
84+
- Implements callbacks for output, status, and data retrieval
85+
- Emits Qt signals to integrate with existing architecture
86+
- **xyce.cpp/h**: Xyce simulator support
87+
- **spicecompat.cpp/h**: SPICE compatibility layer
88+
- **qucs2spice.cpp/h**: Qucs schematic to SPICE netlist converter
89+
90+
### Visualization (`qucs/diagrams/`)
91+
- **diagram.cpp/h**: Base diagram/graph classes
92+
- **graph.cpp/h**: Data plotting
93+
- **marker.cpp/h**: Graph markers for measurements
94+
- **curvediagram.h**, **polardiagram.h**, etc.: Specialized plot types
95+
96+
### Dialogs (`qucs/dialogs/`)
97+
Qt dialog implementations for settings, component properties, import/export, etc.
98+
99+
### Utility Tools
100+
Separate GUI applications built alongside main app:
101+
- **qucs-filter/**: Filter design tool
102+
- **qucs-attenuator/**: Attenuator calculator
103+
- **qucs-transcalc/**: Transmission line calculator
104+
- **qucs-activefilter/**: Active filter design
105+
- **qucs-powercombining/**: Power combining calculator
106+
- **qucs-s-spar-viewer/**: S-parameter viewer
107+
108+
### Libraries (`library/`)
109+
SPICE model libraries (`.lib` files) for various component types: BJT, MOSFETs, diodes, ICs, etc.
110+
111+
### Geometry System (`qucs/geometry/`)
112+
Header-only geometry library for shapes and points. Has unit tests.
113+
114+
## Code Style
115+
116+
### C++ Standards
117+
- **C++20**: Standard for new code
118+
- **Qt6**: All Qt code uses Qt6 APIs
119+
- **Modern C++**: Prefer C++17/20 features over legacy approaches
120+
121+
### Naming Conventions
122+
- **Variables/functions**: `camelCaseWithSmallFirstLetter`
123+
- **Classes**: CapitalizedCamelCase (Qt style)
124+
125+
### Formatting
126+
- Use `clang-format` for all changes (config in `.clang-format`)
127+
- Format specific lines: `clang-format --lines=<start>:<end> path/to/file`
128+
- Key settings: 80 column limit, 2-space indent, pointer-left (`int* ptr`), braces on same line
129+
- **Always use braces** for `if`, `for`, `while`, etc., even for single statements
130+
131+
### Required Patterns
132+
```cpp
133+
// Bad - forbidden
134+
if (condition)
135+
doSomething();
136+
137+
// Good - required
138+
if (condition) {
139+
doSomething();
140+
}
141+
```
142+
143+
## Git Workflow
144+
145+
### Branch Strategy
146+
- **`current`**: Main development branch (use for PRs with new features)
147+
- **`release/YY.N`**: Release branches (use for bugfix PRs)
148+
- **`master`**: Stable releases
149+
150+
### Commit Messages
151+
Format (max 80 columns):
152+
```
153+
Brief description on first line
154+
155+
Optional detailed description after blank line.
156+
Can span multiple lines.
157+
```
158+
159+
Examples from history:
160+
- `fix(WireLabel::mirrorX/Y): Handle axis input`
161+
- `Fix Monte Carlo ngspice template`
162+
163+
### Pull Requests
164+
- **Bugfixes**: Base on `release/YY.N`, prefix branch with issue number (e.g., `310-fix-window-size`)
165+
- **Features**: Base on `current`
166+
- One logical unit per PR (single bugfix or feature)
167+
- Atomic commits, easy to review
168+
- PRs must merge without conflicts
169+
170+
## CI/CD
171+
172+
GitHub Actions workflow (`.github/workflows/deploy.yml`):
173+
- Builds on Linux (AppImage, Qt6)
174+
- Builds on push to `master`, `current`, `release/*` branches and tags
175+
- Check status: `gh pr checks` or `gh pr checks --watch`
176+
177+
## LSP/IDE Support
178+
179+
### clangd Setup
180+
`compile_commands.json` generated by CMake in `builddir/`:
181+
```bash
182+
cd builddir
183+
cmake ..
184+
cd ..
185+
ln -s ./builddir/compile_commands.json compile_commands.json
186+
```
187+
188+
Configuration in `.clangd` file.
189+
190+
## Project-Specific Notes
191+
192+
### Qt Integration
193+
- Uses Qt `.ui` files for some dialogs (auto-compiled by CMake via `CMAKE_AUTOUIC`)
194+
- Qt MOC enabled (`CMAKE_AUTOMOC`)
195+
- Resource files (`.qrc`) for bitmaps/icons
196+
197+
### Simulation Flow
198+
1. User creates schematic in GUI
199+
2. Schematic converted to SPICE netlist (via `qucs2spice`)
200+
3. Netlist sent to simulation kernel (typically ngspice)
201+
4. Results parsed and visualized in diagrams
202+
203+
### Submodules
204+
- `qucsator_rf/` is a git submodule (currently empty placeholder)
205+
- Must run `git submodule init && git submodule update` after clone
206+
207+
## Common Tasks
208+
209+
### Adding a New Component
210+
1. Create `.cpp` and `.h` files in `qucs/components/`
211+
2. Inherit from base `Component` class
212+
3. Implement properties, SPICE conversion, and visual representation
213+
4. Add to component registry in components system
214+
215+
### Debugging Build Issues
216+
- Check component library files in `library/` are installed
217+
- Verify Qt6 development packages present
218+
- Ensure flex/bison/gperf available for parser generation
219+
- Review CMake output for missing dependencies
220+
221+
### Working with Schematic Editor
222+
Key interaction code in `mouseactions.cpp` and `schematic.cpp`. Canvas uses custom Qt3-compatibility scroll view (`Q3ScrollView`).
223+
224+
### Translation Updates
225+
Run with `-DUPDATE_TRANSLATIONS=ON` to update `.ts` translation files from source.

CMakeLists.txt

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,35 @@ if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
5151
add_compile_definitions(QT_NO_DEBUG_OUTPUT)
5252
endif()
5353

54+
# Simulator backend options
55+
option(WITH_NGSPICE_SHARED "Enable ngspice shared library support" OFF)
56+
option(WITH_EXTERNAL_SIMULATORS "Enable external simulator support (QProcess-based)" ON)
57+
58+
if(WITH_NGSPICE_SHARED)
59+
find_library(NGSPICE_LIBRARY NAMES ngspice libngspice)
60+
find_path(NGSPICE_INCLUDE_DIR ngspice/sharedspice.h)
61+
62+
if(NGSPICE_LIBRARY AND NGSPICE_INCLUDE_DIR)
63+
message(STATUS "Found ngspice shared library: ${NGSPICE_LIBRARY}")
64+
message(STATUS "Found ngspice headers: ${NGSPICE_INCLUDE_DIR}")
65+
set(NGSPICE_SHARED 1)
66+
else()
67+
message(WARNING "Ngspice shared library not found. WITH_NGSPICE_SHARED disabled.")
68+
set(WITH_NGSPICE_SHARED OFF)
69+
set(NGSPICE_SHARED 0)
70+
endif()
71+
else()
72+
set(NGSPICE_SHARED 0)
73+
endif()
74+
75+
if(WITH_EXTERNAL_SIMULATORS)
76+
set(EXTERNAL_SIMULATORS 1)
77+
message(STATUS "External simulator support enabled")
78+
else()
79+
set(EXTERNAL_SIMULATORS 0)
80+
message(STATUS "External simulator support disabled")
81+
endif()
82+
5483
enable_testing()
5584

5685
add_subdirectory( qucs )

config.h.cmake

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,9 @@
88
#define WITH_SPICE "@WITH_SPICE@"
99

1010
#define GIT "@GIT@"
11+
12+
#define WASM_BUILD "@WASM_BUILD"
13+
14+
/* Simulator backend configuration */
15+
#define NGSPICE_SHARED @NGSPICE_SHARED@
16+
#define EXTERNAL_SIMULATORS @EXTERNAL_SIMULATORS@

qucs/extsimkernels/CMakeLists.txt

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@
44
INCLUDE_DIRECTORIES( ${CMAKE_CURRENT_SOURCE_DIR}
55
${CMAKE_CURRENT_BINARY_DIR} )
66

7+
# Add ngspice include directory if shared library support is enabled
8+
if(WITH_NGSPICE_SHARED AND NGSPICE_INCLUDE_DIR)
9+
INCLUDE_DIRECTORIES(${NGSPICE_INCLUDE_DIR})
10+
endif()
11+
712
#INCLUDES = $(X11_INCLUDES) $(QT_INCLUDES) -I$(top_srcdir)/qucs
813

914
SET(EXTSIMKERNELS_HDRS
@@ -23,6 +28,11 @@ spicelibcompdialog.h
2328
CdlSettingsDialog.h
2429
)
2530

31+
# Add ngspice_shared header if enabled
32+
if(WITH_NGSPICE_SHARED)
33+
list(APPEND EXTSIMKERNELS_HDRS ngspice_shared.h)
34+
endif()
35+
2636
SET(EXTSIMKERNELS_SRCS
2737
externsimdialog.cpp
2838
abstractspicekernel.cpp
@@ -41,6 +51,11 @@ spicelibcompdialog.cpp
4151
CdlSettingsDialog.cpp
4252
)
4353

54+
# Add ngspice_shared source if enabled
55+
if(WITH_NGSPICE_SHARED)
56+
list(APPEND EXTSIMKERNELS_SRCS ngspice_shared.cpp)
57+
endif()
58+
4459
SET(EXTSIMKERNELS_MOC_HDRS
4560
externsimdialog.h
4661
abstractspicekernel.h
@@ -52,10 +67,21 @@ spicelibcompdialog.h
5267
CdlSettingsDialog.h
5368
)
5469

70+
# Add ngspice_shared to MOC headers if enabled
71+
if(WITH_NGSPICE_SHARED)
72+
list(APPEND EXTSIMKERNELS_MOC_HDRS ngspice_shared.h)
73+
endif()
74+
5575
QT6_WRAP_CPP( EXTSIMKERNELS_MOC_SRCS ${EXTSIMKERNELS_MOC_HDRS} )
5676

5777

5878
ADD_LIBRARY(extsimkernels STATIC ${EXTSIMKERNELS_HDRS} ${EXTSIMKERNELS_SRCS} ${EXTSIMKERNELS_MOC_SRCS})
5979

80+
# Link against ngspice shared library if enabled
81+
if(WITH_NGSPICE_SHARED AND NGSPICE_LIBRARY)
82+
target_link_libraries(extsimkernels PUBLIC ${NGSPICE_LIBRARY})
83+
message(STATUS "Linking extsimkernels with ngspice shared library: ${NGSPICE_LIBRARY}")
84+
endif()
85+
6086
ADD_SUBDIRECTORY( xspice )
6187

0 commit comments

Comments
 (0)