You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

436 lines
15 KiB

cmake_minimum_required(VERSION 3.18)
project(pyngspice VERSION 43.0.0 LANGUAGES C CXX)
# ============================================================================
# Options
# ============================================================================
option(BUILD_PYTHON_BINDINGS "Build Python bindings" ON)
option(ENABLE_XSPICE "Enable XSPICE code models" ON)
option(ENABLE_OSDI "Enable OSDI (Verilog-A) support" ON)
option(ENABLE_CIDER "Enable CIDER numerical device models" OFF) # Disabled - needs special KLU setup
option(ENABLE_KLU "Enable KLU sparse matrix solver" OFF) # Disabled - needs complex build setup
# ============================================================================
# Compiler settings
# ============================================================================
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_C_STANDARD 11)
set(CMAKE_C_EXTENSIONS ON) # Use gnu11 instead of c11 for better complex support
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
# Suppress warnings
if(MSVC)
add_compile_options(/W3 /wd4996 /wd4267 /wd4244 /wd4018 /wd4090 /wd4101 /wd4146)
add_definitions(-D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_WARNINGS)
add_definitions(-DWIN32 -D_WINDOWS)
else()
add_compile_options(-Wall -Wno-unused-variable -Wno-unused-function -Wno-sign-compare -Wno-format)
if(CMAKE_C_COMPILER_ID MATCHES "GNU")
add_compile_options(-Wno-maybe-uninitialized -Wno-unused-but-set-variable)
endif()
endif()
# ============================================================================
# Platform detection
# ============================================================================
if(WIN32)
set(PLATFORM_WINDOWS TRUE)
elseif(APPLE)
set(PLATFORM_MACOS TRUE)
elseif(UNIX)
set(PLATFORM_LINUX TRUE)
endif()
# ============================================================================
# Find dependencies
# ============================================================================
find_package(Python3 REQUIRED COMPONENTS Interpreter Development.Module NumPy)
# Find pybind11 — try system install first, then fall back to pip-installed
find_package(pybind11 CONFIG QUIET)
if(NOT pybind11_FOUND)
# pybind11 is a build dependency in pyproject.toml, so pip has already
# installed it into the build environment. Find it via the Python package.
execute_process(
COMMAND ${Python3_EXECUTABLE} -c
"import pybind11; print(pybind11.get_cmake_dir())"
OUTPUT_VARIABLE PYBIND11_CMAKE_DIR
OUTPUT_STRIP_TRAILING_WHITESPACE
RESULT_VARIABLE PYBIND11_RESULT
)
if(PYBIND11_RESULT EQUAL 0)
list(APPEND CMAKE_PREFIX_PATH ${PYBIND11_CMAKE_DIR})
find_package(pybind11 CONFIG REQUIRED)
else()
message(FATAL_ERROR
"pybind11 not found. Install it with: pip install pybind11>=2.11")
endif()
endif()
# Math library on Unix
if(UNIX AND NOT APPLE)
find_library(M_LIBRARY m REQUIRED)
endif()
find_package(Threads REQUIRED)
# ============================================================================
# Source directories
# ============================================================================
set(NGSPICE_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src)
# ============================================================================
# Include directories
# ============================================================================
set(NGSPICE_INCLUDE_DIRS
${CMAKE_CURRENT_SOURCE_DIR}/visualc/src/include # Windows config.h
${NGSPICE_SRC}
${NGSPICE_SRC}/include
${NGSPICE_SRC}/include/cppduals # For HICUM2 duals library
${NGSPICE_SRC}/include/ngspice
${NGSPICE_SRC}/spicelib/devices
${NGSPICE_SRC}/spicelib/analysis
${NGSPICE_SRC}/spicelib/parser
${NGSPICE_SRC}/maths/dense
${NGSPICE_SRC}/maths/sparse
${NGSPICE_SRC}/maths/ni
${NGSPICE_SRC}/maths/deriv
${NGSPICE_SRC}/maths/cmaths
${NGSPICE_SRC}/maths/misc
${NGSPICE_SRC}/maths/poly
${NGSPICE_SRC}/maths/fft
${NGSPICE_SRC}/frontend
${NGSPICE_SRC}/frontend/plotting
${NGSPICE_SRC}/frontend/parser
${NGSPICE_SRC}/frontend/help
${NGSPICE_SRC}/frontend/numparam
${NGSPICE_SRC}/frontend/trannoise
${NGSPICE_SRC}/misc
${NGSPICE_SRC}/ciderlib/input
${NGSPICE_SRC}/ciderlib/support
${NGSPICE_SRC}/ciderlib/oned
${NGSPICE_SRC}/ciderlib/twod
${NGSPICE_SRC}/xspice/cm
${NGSPICE_SRC}/xspice/cmpp
${NGSPICE_SRC}/xspice/evt
${NGSPICE_SRC}/xspice/enh
${NGSPICE_SRC}/xspice/ipc
${NGSPICE_SRC}/xspice/idn
${NGSPICE_SRC}/xspice/mif
${NGSPICE_SRC}/xspice/icm
${NGSPICE_SRC}/osdi
)
# ============================================================================
# Build date/version info
# ============================================================================
string(TIMESTAMP NGSPICE_BUILD_DATE "%Y-%m-%d")
# ============================================================================
# Compile definitions
# ============================================================================
set(NGSPICE_DEFINITIONS
-DNGSPICEDLL
-DSHARED_MODULE
-DSIMULATOR
-DHAS_PROGREP
-DNG_SHARED_BUILD
-DNGSPICEBUILDDATE="${NGSPICE_BUILD_DATE}"
)
# MinGW-specific: nothing special needed now since we patched cmath1.c
if(ENABLE_XSPICE)
list(APPEND NGSPICE_DEFINITIONS -DXSPICE)
endif()
if(ENABLE_OSDI)
list(APPEND NGSPICE_DEFINITIONS -DOSDI)
endif()
if(ENABLE_CIDER)
list(APPEND NGSPICE_DEFINITIONS -DCIDER)
endif()
if(ENABLE_KLU)
list(APPEND NGSPICE_DEFINITIONS -DKLU)
endif()
# ============================================================================
# Collect ngspice source files
# ============================================================================
# Frontend sources
file(GLOB FRONTEND_SOURCES
${NGSPICE_SRC}/frontend/*.c
)
# Frontend subdirectories
file(GLOB FRONTEND_PARSER_SOURCES ${NGSPICE_SRC}/frontend/parser/*.c)
file(GLOB FRONTEND_NUMPARAM_SOURCES ${NGSPICE_SRC}/frontend/numparam/*.c)
file(GLOB FRONTEND_TRANNOISE_SOURCES ${NGSPICE_SRC}/frontend/trannoise/*.c)
file(GLOB FRONTEND_HELP_SOURCES ${NGSPICE_SRC}/frontend/help/*.c)
file(GLOB FRONTEND_PLOTTING_SOURCES ${NGSPICE_SRC}/frontend/plotting/*.c)
# Math sources
file(GLOB MATHS_SPARSE_SOURCES ${NGSPICE_SRC}/maths/sparse/*.c)
file(GLOB MATHS_DENSE_SOURCES ${NGSPICE_SRC}/maths/dense/*.c)
file(GLOB MATHS_NI_SOURCES ${NGSPICE_SRC}/maths/ni/*.c)
file(GLOB MATHS_DERIV_SOURCES ${NGSPICE_SRC}/maths/deriv/*.c)
file(GLOB MATHS_CMATHS_SOURCES ${NGSPICE_SRC}/maths/cmaths/*.c)
file(GLOB MATHS_MISC_SOURCES ${NGSPICE_SRC}/maths/misc/*.c)
file(GLOB MATHS_POLY_SOURCES ${NGSPICE_SRC}/maths/poly/*.c)
file(GLOB MATHS_FFT_SOURCES ${NGSPICE_SRC}/maths/fft/*.c)
# Spicelib sources
file(GLOB SPICELIB_ANALYSIS_SOURCES ${NGSPICE_SRC}/spicelib/analysis/*.c)
file(GLOB SPICELIB_PARSER_SOURCES ${NGSPICE_SRC}/spicelib/parser/*.c)
# Device sources - collect all device model subdirectories
file(GLOB_RECURSE SPICELIB_DEVICES_C_SOURCES ${NGSPICE_SRC}/spicelib/devices/*.c)
# HICUM2 .cpp files use the "duals" library for automatic differentiation (header-only, included in ngspice)
file(GLOB_RECURSE SPICELIB_DEVICES_CPP_SOURCES ${NGSPICE_SRC}/spicelib/devices/*.cpp)
set(SPICELIB_DEVICES_SOURCES ${SPICELIB_DEVICES_C_SOURCES} ${SPICELIB_DEVICES_CPP_SOURCES})
# Exclude KLU-specific binding files when KLU is disabled
if(NOT ENABLE_KLU)
list(FILTER SPICELIB_DEVICES_SOURCES EXCLUDE REGEX "bindCSC\\.c$")
endif()
# Misc sources
file(GLOB MISC_SOURCES ${NGSPICE_SRC}/misc/*.c)
# CIDER sources (if enabled)
if(ENABLE_CIDER)
file(GLOB CIDER_INPUT_SOURCES ${NGSPICE_SRC}/ciderlib/input/*.c)
file(GLOB CIDER_SUPPORT_SOURCES ${NGSPICE_SRC}/ciderlib/support/*.c)
file(GLOB CIDER_ONED_SOURCES ${NGSPICE_SRC}/ciderlib/oned/*.c)
file(GLOB CIDER_TWOD_SOURCES ${NGSPICE_SRC}/ciderlib/twod/*.c)
set(CIDER_SOURCES
${CIDER_INPUT_SOURCES}
${CIDER_SUPPORT_SOURCES}
${CIDER_ONED_SOURCES}
${CIDER_TWOD_SOURCES}
)
endif()
# XSPICE sources (if enabled)
if(ENABLE_XSPICE)
file(GLOB XSPICE_CM_SOURCES ${NGSPICE_SRC}/xspice/cm/*.c)
file(GLOB XSPICE_EVT_SOURCES ${NGSPICE_SRC}/xspice/evt/*.c)
file(GLOB XSPICE_ENH_SOURCES ${NGSPICE_SRC}/xspice/enh/*.c)
file(GLOB XSPICE_IPC_SOURCES ${NGSPICE_SRC}/xspice/ipc/*.c)
file(GLOB XSPICE_IDN_SOURCES ${NGSPICE_SRC}/xspice/idn/*.c)
file(GLOB XSPICE_MIF_SOURCES ${NGSPICE_SRC}/xspice/mif/*.c)
# ICM (code models) built separately
set(XSPICE_SOURCES
${XSPICE_CM_SOURCES}
${XSPICE_EVT_SOURCES}
${XSPICE_ENH_SOURCES}
${XSPICE_IPC_SOURCES}
${XSPICE_IDN_SOURCES}
${XSPICE_MIF_SOURCES}
)
# Exclude KLU-specific binding files when KLU is disabled
if(NOT ENABLE_KLU)
list(FILTER XSPICE_SOURCES EXCLUDE REGEX "bindCSC\\.c$")
endif()
endif()
# OSDI sources (if enabled)
if(ENABLE_OSDI)
file(GLOB OSDI_SOURCES ${NGSPICE_SRC}/osdi/*.c)
endif()
# KLU sources (if enabled)
if(ENABLE_KLU)
# KLU sources are in src/maths/KLU directory
file(GLOB KLU_SOURCES ${NGSPICE_SRC}/maths/KLU/*.c)
list(APPEND NGSPICE_INCLUDE_DIRS ${NGSPICE_SRC}/maths/KLU)
endif()
# Main ngspice files
set(NGSPICE_MAIN_SOURCES
${NGSPICE_SRC}/sharedspice.c
${NGSPICE_SRC}/conf.c
${NGSPICE_SRC}/ngspice.c # Contains SIMinfo definition
)
# MSVC compatibility
if(MSVC AND EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/visualc/src/msvc-compat.c)
list(APPEND NGSPICE_MAIN_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/visualc/src/msvc-compat.c
)
endif()
# ============================================================================
# Combine all ngspice sources
# ============================================================================
set(ALL_NGSPICE_SOURCES
${NGSPICE_MAIN_SOURCES}
${FRONTEND_SOURCES}
${FRONTEND_PARSER_SOURCES}
${FRONTEND_NUMPARAM_SOURCES}
${FRONTEND_TRANNOISE_SOURCES}
${FRONTEND_HELP_SOURCES}
${FRONTEND_PLOTTING_SOURCES}
${MATHS_SPARSE_SOURCES}
${MATHS_DENSE_SOURCES}
${MATHS_NI_SOURCES}
${MATHS_DERIV_SOURCES}
${MATHS_CMATHS_SOURCES}
${MATHS_MISC_SOURCES}
${MATHS_POLY_SOURCES}
${MATHS_FFT_SOURCES}
${SPICELIB_ANALYSIS_SOURCES}
${SPICELIB_PARSER_SOURCES}
${SPICELIB_DEVICES_SOURCES}
${MISC_SOURCES}
)
if(ENABLE_CIDER)
list(APPEND ALL_NGSPICE_SOURCES ${CIDER_SOURCES})
endif()
if(ENABLE_XSPICE)
list(APPEND ALL_NGSPICE_SOURCES ${XSPICE_SOURCES})
endif()
if(ENABLE_OSDI)
list(APPEND ALL_NGSPICE_SOURCES ${OSDI_SOURCES})
endif()
if(ENABLE_KLU AND DEFINED KLU_SOURCES)
list(APPEND ALL_NGSPICE_SOURCES ${KLU_SOURCES})
endif()
# Remove files that cause conflicts or aren't needed for shared library
list(FILTER ALL_NGSPICE_SOURCES EXCLUDE REGEX "main\\.c$")
# Note: ngspice.c is INCLUDED - it contains SIMinfo but no main()
list(FILTER ALL_NGSPICE_SOURCES EXCLUDE REGEX "winmain\\.c$")
list(FILTER ALL_NGSPICE_SOURCES EXCLUDE REGEX "tclspice\\.c$")
list(FILTER ALL_NGSPICE_SOURCES EXCLUDE REGEX "ngnutmeg\\.c$")
list(FILTER ALL_NGSPICE_SOURCES EXCLUDE REGEX "nghelp\\.c$")
list(FILTER ALL_NGSPICE_SOURCES EXCLUDE REGEX "ngsconvert\\.c$")
list(FILTER ALL_NGSPICE_SOURCES EXCLUDE REGEX "ngmultidec\\.c$")
list(FILTER ALL_NGSPICE_SOURCES EXCLUDE REGEX "ngproc2mod\\.c$")
list(FILTER ALL_NGSPICE_SOURCES EXCLUDE REGEX "makeidx\\.c$")
list(FILTER ALL_NGSPICE_SOURCES EXCLUDE REGEX "hist_info\\.c$")
list(FILTER ALL_NGSPICE_SOURCES EXCLUDE REGEX "testcommands\\.c$")
list(FILTER ALL_NGSPICE_SOURCES EXCLUDE REGEX "test_accuracy\\.c$")
# Exclude ndev (network device) - uses Unix socket headers
list(FILTER ALL_NGSPICE_SOURCES EXCLUDE REGEX "/ndev/")
# Exclude CIDER-dependent numerical device models when CIDER is disabled
if(NOT ENABLE_CIDER)
list(FILTER ALL_NGSPICE_SOURCES EXCLUDE REGEX "/nbjt/")
list(FILTER ALL_NGSPICE_SOURCES EXCLUDE REGEX "/nbjt2/")
list(FILTER ALL_NGSPICE_SOURCES EXCLUDE REGEX "/numd/")
list(FILTER ALL_NGSPICE_SOURCES EXCLUDE REGEX "/numd2/")
list(FILTER ALL_NGSPICE_SOURCES EXCLUDE REGEX "/numos/")
endif()
# ============================================================================
# Create ngspice static library
# ============================================================================
add_library(ngspice_core STATIC ${ALL_NGSPICE_SOURCES})
target_include_directories(ngspice_core PUBLIC ${NGSPICE_INCLUDE_DIRS})
target_compile_definitions(ngspice_core PUBLIC ${NGSPICE_DEFINITIONS})
if(UNIX AND NOT APPLE)
target_link_libraries(ngspice_core PUBLIC ${M_LIBRARY})
endif()
target_link_libraries(ngspice_core PUBLIC Threads::Threads)
# Windows-specific libraries
if(WIN32)
target_link_libraries(ngspice_core PUBLIC shlwapi)
endif()
# ============================================================================
# Python extension sources
# ============================================================================
set(PYTHON_EXT_SOURCES
${NGSPICE_SRC}/bindings/module.cpp
${NGSPICE_SRC}/cpp/simulator.cpp
${NGSPICE_SRC}/cpp/callbacks.cpp
${NGSPICE_SRC}/cpp/sim_runner.cpp
${NGSPICE_SRC}/cpp/raw_read.cpp
${NGSPICE_SRC}/cpp/trace.cpp
)
# ============================================================================
# Create Python module
# ============================================================================
pybind11_add_module(_pyngspice MODULE ${PYTHON_EXT_SOURCES})
target_include_directories(_pyngspice PRIVATE
${NGSPICE_INCLUDE_DIRS}
${NGSPICE_SRC}/cpp
${Python3_INCLUDE_DIRS}
${Python3_NumPy_INCLUDE_DIRS}
)
target_compile_definitions(_pyngspice PRIVATE
NGSPICE_PYTHON_MODULE
VERSION_STR="${PROJECT_VERSION}"
${NGSPICE_DEFINITIONS}
)
# Link against ngspice core and Python
target_link_libraries(_pyngspice PRIVATE
ngspice_core
Python3::NumPy
)
if(APPLE)
target_link_libraries(_pyngspice PRIVATE "-framework Accelerate")
endif()
# Output .pyd directly into pyngspice/ for inplace editable install
set_target_properties(_pyngspice PROPERTIES
LIBRARY_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/pyngspice
)
# MinGW: statically link all runtime DLLs (ship zero DLLs)
if(MINGW)
target_link_options(_pyngspice PRIVATE -static-libgcc -static-libstdc++)
target_link_libraries(_pyngspice PRIVATE
-Wl,-Bstatic,--whole-archive -lwinpthread -Wl,--no-whole-archive,-Bdynamic
)
endif()
# ============================================================================
# Install (for wheel builds)
# ============================================================================
install(TARGETS _pyngspice
LIBRARY DESTINATION pyngspice
RUNTIME DESTINATION pyngspice
)
install(FILES
${CMAKE_CURRENT_SOURCE_DIR}/pyngspice/__init__.py
${CMAKE_CURRENT_SOURCE_DIR}/pyngspice/runner.py
${CMAKE_CURRENT_SOURCE_DIR}/pyngspice/netlist.py
DESTINATION pyngspice
)
# ============================================================================
# Summary
# ============================================================================
message(STATUS "")
message(STATUS "========================================")
message(STATUS "pyngspice Configuration")
message(STATUS "========================================")
message(STATUS " Version: ${PROJECT_VERSION}")
message(STATUS " Python: ${Python3_EXECUTABLE}")
message(STATUS " NumPy: ${Python3_NumPy_VERSION}")
message(STATUS " pybind11: ${pybind11_VERSION}")
message(STATUS " XSPICE: ${ENABLE_XSPICE}")
message(STATUS " OSDI: ${ENABLE_OSDI}")
message(STATUS " CIDER: ${ENABLE_CIDER}")
message(STATUS " KLU: ${ENABLE_KLU}")
message(STATUS " Source files: ${CMAKE_CURRENT_LIST_DIR}")
message(STATUS "========================================")
message(STATUS "")