From 60047128b85886e9845c2a1d238a18390ef52d6a Mon Sep 17 00:00:00 2001 From: Chad <167274875+UnsignedChad@users.noreply.github.com> Date: Tue, 9 Jun 2026 18:34:27 -0400 Subject: [PATCH] cmake: make the repo consumable via add_subdirectory / FetchContent the kicad plugin repos will pin circuitcore as a dependency instead of copying code, so the build has to behave as a guest: - CMAKE_SOURCE_DIR leaked the parent projects root in 6 places (third_party includes on ui/pdnkit_pi/sikit_si, the repo-root include on both widgets libs, the vtk patch script includes in mpkit/widgets). all now use circuitcore_SOURCE_DIR. - new CIRCUITCORE_BUILD_APPS option gates the four executables + CLI11. apps, tests and mpkit widgets (vtk) default OFF when circuitcore is not the top-level project, ON as before when it is. - stop FORCE-caching CMAKE_BUILD_TYPE when embedded. - aliases for the engines: pdnkit::pi, sikit::si, emikit::emi. - bare PUBLIC include dirs wrapped in BUILD_INTERFACE (field, emikit, mpkit, kits) so install(EXPORT) stays possible later. - tests/consumer: standalone project that add_subdirectory()s the repo, links circuitcore::kicad + pdnkit::widgets + emikit::emi, parses the tiny_pdn fixture and checks a target-z number. wired into ci after the test step, including asserts that apps/tests stayed off. - readme: short section on consuming the repo + target list. no source changes, no behavior change for the standalone build. --- .github/workflows/ci.yml | 12 ++++++++ CMakeLists.txt | 31 +++++++++++++++++---- README.md | 20 ++++++++++++++ emikit/CMakeLists.txt | 25 ++++++++++------- field/CMakeLists.txt | 2 +- mpkit/CMakeLists.txt | 2 +- mpkit/widgets/CMakeLists.txt | 6 ++-- pdnkit/CMakeLists.txt | 50 +++++++++++++++++---------------- sikit/CMakeLists.txt | 52 +++++++++++++++++++---------------- tests/consumer/CMakeLists.txt | 28 +++++++++++++++++++ tests/consumer/main.cpp | 36 ++++++++++++++++++++++++ ui/CMakeLists.txt | 2 +- 12 files changed, 197 insertions(+), 69 deletions(-) create mode 100644 tests/consumer/CMakeLists.txt create mode 100644 tests/consumer/main.cpp diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 07f0224..3fefac6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -40,3 +40,15 @@ jobs: - name: Test run: ctest --test-dir build --output-on-failure --parallel + + # Prove the repo still works as an embedded dependency (the path + # the kicad plugin repos use): the consumer project + # add_subdirectory()s this checkout with apps, tests and mpkit + # widgets defaulted OFF. + - name: Consumer smoke (embedded use) + run: | + cmake -S tests/consumer -B build-consumer -G Ninja \ + -DCMAKE_BUILD_TYPE=Release -DCIRCUITCORE_DIR=$PWD + cmake --build build-consumer --parallel + ./build-consumer/consumer_smoke pdnkit/tests/fixtures/tiny_pdn.kicad_pcb + test ! -e build-consumer/circuitcore/pdnkit/pdnkit diff --git a/CMakeLists.txt b/CMakeLists.txt index 5e19d1c..7bf3bcd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,15 @@ cmake_minimum_required(VERSION 3.20) project(circuitcore LANGUAGES CXX VERSION 0.1.0) +# Standalone build vs embedded (add_subdirectory / FetchContent from a +# parent project). Apps, tests and the VTK-heavy mpkit widgets default +# OFF when embedded so a consumer gets just the libraries. +if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) + set(CIRCUITCORE_TOP_LEVEL ON) +else() + set(CIRCUITCORE_TOP_LEVEL OFF) +endif() + set(CMAKE_CXX_STANDARD 23) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) @@ -75,21 +84,30 @@ if(MSVC) ) endif() -if(NOT CMAKE_BUILD_TYPE) +# Only steer the build type when this is our own build; never clobber +# a parent project's cache. +if(CIRCUITCORE_TOP_LEVEL AND NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE Release CACHE STRING "" FORCE) endif() option(CIRCUITCORE_BUILD_MPKIT_WIDGETS "Build mpkit::widgets (pulls in VTK via FetchContent, adds ~20 min)" - ON) + ${CIRCUITCORE_TOP_LEVEL}) -option(CIRCUITCORE_BUILD_TESTS "Build all test suites" ON) +option(CIRCUITCORE_BUILD_TESTS "Build all test suites" + ${CIRCUITCORE_TOP_LEVEL}) + +option(CIRCUITCORE_BUILD_APPS + "Build the GUI/CLI executables (pdnkit, sikit, emikit, studio)" + ${CIRCUITCORE_TOP_LEVEL}) # --- Shared dependencies --- find_package(Qt6 REQUIRED COMPONENTS Widgets OpenGL OpenGLWidgets) find_package(Eigen3 REQUIRED NO_MODULE) find_package(spdlog REQUIRED) -find_package(CLI11 REQUIRED) +if(CIRCUITCORE_BUILD_APPS) + find_package(CLI11 REQUIRED) # only the executables parse arguments +endif() # Cross-compiler warning preset. GCC/Clang get the full -Wall -Wextra # -Wpedantic trio; MSVC gets /W4 (its /Wall is famously too noisy for @@ -140,8 +158,9 @@ add_subdirectory(pdnkit) add_subdirectory(sikit) add_subdirectory(emikit) add_subdirectory(mpkit) -add_subdirectory(studio) # circuitcore_studio -- unified browser-tab GUI - # (see sikit/MIGRATION.md) +if(CIRCUITCORE_BUILD_APPS) + add_subdirectory(studio) # circuitcore_studio -- unified browser-tab GUI +endif() # --- Test discovery for the core libs --- if(CIRCUITCORE_BUILD_TESTS) diff --git a/README.md b/README.md index 96a6029..4c956a0 100644 --- a/README.md +++ b/README.md @@ -155,6 +155,26 @@ Binaries land in `build/pdnkit/pdnkit`, `build/sikit/sikit`, - Sikit FDTD validated against analytic stripline + planar-waveguide cases. +## Using circuitcore as a dependency + +Consumable via add_subdirectory or FetchContent; apps, tests and the +VTK-backed mpkit widgets switch OFF automatically when circuitcore is +not the top-level project. + +```cmake +include(FetchContent) +FetchContent_Declare(circuitcore + GIT_REPOSITORY https://github.com/UnsignedChad/circuitcore.git + GIT_TAG v0.1.0-alpha.4) +FetchContent_MakeAvailable(circuitcore) + +target_link_libraries(myplugin PRIVATE pdnkit::widgets circuitcore::kicad) +``` + +Library targets: `circuitcore::{board,sexpr,netlist,kicad,field,ui}`, +`pdnkit::{pi,widgets}`, `sikit::{si,widgets}`, `emikit::emi`, +`mpkit::{mp,widgets}`. See `tests/consumer/` for a minimal consumer. + ## Contributing See `CONTRIBUTING.md`. CI runs gcc-13 on Ubuntu 24.04. CODEOWNERS gates diff --git a/emikit/CMakeLists.txt b/emikit/CMakeLists.txt index 11e7705..3860234 100644 --- a/emikit/CMakeLists.txt +++ b/emikit/CMakeLists.txt @@ -8,19 +8,24 @@ add_library(emikit_emi STATIC emi/Masks.cpp emi/BoardAnalysis.cpp ) -target_include_directories(emikit_emi PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) +add_library(emikit::emi ALIAS emikit_emi) +target_include_directories(emikit_emi PUBLIC + $ +) target_link_libraries(emikit_emi PUBLIC circuitcore::board) circuitcore_warnings(emikit_emi) -add_executable(emikit - main.cpp -) -target_link_libraries(emikit PRIVATE - emikit_emi - circuitcore::kicad - CLI11::CLI11 -) -circuitcore_warnings(emikit) +if(CIRCUITCORE_BUILD_APPS) + add_executable(emikit + main.cpp + ) + target_link_libraries(emikit PRIVATE + emikit_emi + circuitcore::kicad + CLI11::CLI11 + ) + circuitcore_warnings(emikit) +endif() # emikit_validate_ti reconstructs a vendor reference dataset (TI # ADS8686SEVM-PDK) and compares emikits FAR-field prediction. Useful diff --git a/field/CMakeLists.txt b/field/CMakeLists.txt index b2eb145..09b50dc 100644 --- a/field/CMakeLists.txt +++ b/field/CMakeLists.txt @@ -16,7 +16,7 @@ add_library(circuitcore_field STATIC add_library(circuitcore::field ALIAS circuitcore_field) target_include_directories(circuitcore_field PUBLIC - ${CMAKE_CURRENT_SOURCE_DIR}/include + $ ) circuitcore_warnings(circuitcore_field) diff --git a/mpkit/CMakeLists.txt b/mpkit/CMakeLists.txt index 12ac330..03a1136 100644 --- a/mpkit/CMakeLists.txt +++ b/mpkit/CMakeLists.txt @@ -40,7 +40,7 @@ add_library(mpkit_mp STATIC add_library(mpkit::mp ALIAS mpkit_mp) target_include_directories(mpkit_mp PUBLIC - ${CMAKE_CURRENT_SOURCE_DIR} + $ ) target_link_libraries(mpkit_mp PUBLIC diff --git a/mpkit/widgets/CMakeLists.txt b/mpkit/widgets/CMakeLists.txt index 766319e..1798b5d 100644 --- a/mpkit/widgets/CMakeLists.txt +++ b/mpkit/widgets/CMakeLists.txt @@ -97,8 +97,8 @@ else() # MSVC removed that type outright; patch the branch out so the # diy2 fmt compiles on VS 17.10+ / VS 18 Insiders. no-op on linux # / older MSVC where the branch was harmless anyway. - include("${CMAKE_SOURCE_DIR}/cmake/patches/patch_vtk_diy2_fmt.cmake") - include("${CMAKE_SOURCE_DIR}/cmake/patches/patch_vtk_smp_sequential.cmake") + include("${circuitcore_SOURCE_DIR}/cmake/patches/patch_vtk_diy2_fmt.cmake") + include("${circuitcore_SOURCE_DIR}/cmake/patches/patch_vtk_smp_sequential.cmake") endif() # MPKIT_USE_SYSTEM_VTK add_library(mpkit_widgets STATIC @@ -108,7 +108,7 @@ add_library(mpkit_widgets STATIC add_library(mpkit::widgets ALIAS mpkit_widgets) target_include_directories(mpkit_widgets PUBLIC - ${CMAKE_CURRENT_SOURCE_DIR}/include + $ ) set_target_properties(mpkit_widgets PROPERTIES diff --git a/pdnkit/CMakeLists.txt b/pdnkit/CMakeLists.txt index 0a34c27..c9df825 100644 --- a/pdnkit/CMakeLists.txt +++ b/pdnkit/CMakeLists.txt @@ -23,9 +23,10 @@ add_library(pdnkit_pi STATIC StackupWriter.cpp render/IrResultMesh.cpp ) +add_library(pdnkit::pi ALIAS pdnkit_pi) target_include_directories(pdnkit_pi PUBLIC - ${CMAKE_CURRENT_SOURCE_DIR} - ${CMAKE_SOURCE_DIR}/third_party + $ + $ ) target_link_libraries(pdnkit_pi PUBLIC circuitcore::board @@ -70,8 +71,9 @@ add_library(pdnkit_widgets STATIC add_library(pdnkit::widgets ALIAS pdnkit_widgets) set_target_properties(pdnkit_widgets PROPERTIES AUTOMOC ON) target_include_directories(pdnkit_widgets PUBLIC - ${CMAKE_CURRENT_SOURCE_DIR} - ${CMAKE_SOURCE_DIR} # so studio can use "pdnkit/PcbCanvas.h" etc. + $ + # repo root, so studio + downstream apps can use "pdnkit/PcbCanvas.h" + $ ) target_link_libraries(pdnkit_widgets PUBLIC circuitcore::ui @@ -83,25 +85,27 @@ target_link_libraries(pdnkit_widgets PUBLIC circuitcore_warnings(pdnkit_widgets) # GUI binary. Needs the KiCad adapter to open files, plus Qt. -add_executable(pdnkit - main.cpp - MainWindow.cpp -) -set_target_properties(pdnkit PROPERTIES - AUTOMOC ON - AUTOUIC ON - AUTORCC ON -) -target_link_libraries(pdnkit PRIVATE - pdnkit::widgets - pdnkit_pi - circuitcore::kicad - Qt6::Widgets - Qt6::OpenGLWidgets - Qt6::OpenGL - CLI11::CLI11 -) -circuitcore_warnings(pdnkit) +if(CIRCUITCORE_BUILD_APPS) + add_executable(pdnkit + main.cpp + MainWindow.cpp + ) + set_target_properties(pdnkit PROPERTIES + AUTOMOC ON + AUTOUIC ON + AUTORCC ON + ) + target_link_libraries(pdnkit PRIVATE + pdnkit::widgets + pdnkit_pi + circuitcore::kicad + Qt6::Widgets + Qt6::OpenGLWidgets + Qt6::OpenGL + CLI11::CLI11 + ) + circuitcore_warnings(pdnkit) +endif() if(CIRCUITCORE_BUILD_TESTS) add_subdirectory(tests) diff --git a/sikit/CMakeLists.txt b/sikit/CMakeLists.txt index a49bc28..e28a1d9 100644 --- a/sikit/CMakeLists.txt +++ b/sikit/CMakeLists.txt @@ -56,9 +56,10 @@ add_library(sikit_si STATIC render/Mesher3D.cpp render/GlbLoader.cpp ) +add_library(sikit::si ALIAS sikit_si) target_include_directories(sikit_si PUBLIC - ${CMAKE_CURRENT_SOURCE_DIR} - ${CMAKE_SOURCE_DIR}/third_party + $ + $ ) target_link_libraries(sikit_si PUBLIC @@ -89,8 +90,9 @@ add_library(sikit_widgets STATIC add_library(sikit::widgets ALIAS sikit_widgets) set_target_properties(sikit_widgets PROPERTIES AUTOMOC ON) target_include_directories(sikit_widgets PUBLIC - ${CMAKE_CURRENT_SOURCE_DIR} - ${CMAKE_SOURCE_DIR} # so studio can use "sikit/EyeWindow.h" etc. + $ + # repo root, so studio + downstream apps can use "sikit/EyeWindow.h" + $ ) target_link_libraries(sikit_widgets PUBLIC sikit_si @@ -102,26 +104,28 @@ target_link_libraries(sikit_widgets PUBLIC circuitcore_warnings(sikit_widgets) # GUI binary. Needs the KiCad adapter to open files, plus Qt. -add_executable(sikit - main.cpp - MainWindow.cpp -) -set_target_properties(sikit PROPERTIES - AUTOMOC ON - AUTOUIC ON - AUTORCC ON -) -target_link_libraries(sikit PRIVATE - sikit_si - sikit::widgets - circuitcore::ui # PcbCanvas now subclasses circuitcore::ui::PcbCanvas - circuitcore::kicad - Qt6::Widgets - Qt6::OpenGLWidgets - Qt6::OpenGL - CLI11::CLI11 -) -circuitcore_warnings(sikit) +if(CIRCUITCORE_BUILD_APPS) + add_executable(sikit + main.cpp + MainWindow.cpp + ) + set_target_properties(sikit PROPERTIES + AUTOMOC ON + AUTOUIC ON + AUTORCC ON + ) + target_link_libraries(sikit PRIVATE + sikit_si + sikit::widgets + circuitcore::ui # PcbCanvas subclasses circuitcore::ui::PcbCanvas + circuitcore::kicad + Qt6::Widgets + Qt6::OpenGLWidgets + Qt6::OpenGL + CLI11::CLI11 + ) + circuitcore_warnings(sikit) +endif() if(CIRCUITCORE_BUILD_TESTS) add_subdirectory(tests) diff --git a/tests/consumer/CMakeLists.txt b/tests/consumer/CMakeLists.txt new file mode 100644 index 0000000..71e7a5b --- /dev/null +++ b/tests/consumer/CMakeLists.txt @@ -0,0 +1,28 @@ +# Standalone smoke test that circuitcore works as an embedded dependency +# (add_subdirectory / FetchContent), which is how the kicad plugin repos +# consume it. NOT part of the circuitcore build -- CI configures this +# directory as its own project: +# +# cmake -S tests/consumer -B build-consumer -DCIRCUITCORE_DIR=$PWD +# cmake --build build-consumer +# ./build-consumer/consumer_smoke pdnkit/tests/fixtures/tiny_pdn.kicad_pcb +cmake_minimum_required(VERSION 3.20) +project(circuitcore_consumer LANGUAGES CXX) + +set(CMAKE_CXX_STANDARD 23) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +if(NOT CIRCUITCORE_DIR) + message(FATAL_ERROR "pass -DCIRCUITCORE_DIR=") +endif() + +# Embedded: CIRCUITCORE_BUILD_{APPS,TESTS,MPKIT_WIDGETS} all default OFF, +# so this configure must not require CLI11, Catch2 or VTK. +add_subdirectory(${CIRCUITCORE_DIR} circuitcore) + +add_executable(consumer_smoke main.cpp) +target_link_libraries(consumer_smoke PRIVATE + circuitcore::kicad + pdnkit::widgets # widest closure: pi engine + ui + Qt + emikit::emi +) diff --git a/tests/consumer/main.cpp b/tests/consumer/main.cpp new file mode 100644 index 0000000..3d3604b --- /dev/null +++ b/tests/consumer/main.cpp @@ -0,0 +1,36 @@ +// Embedded-consumption smoke test. Exercises every include style a +// plugin repo will use: prefixed core headers, bare kit-engine headers, +// and the repo-root widgets headers (compile-only -- no QApplication). +#include +#include + +#include "circuitcore/board/Board.h" +#include "circuitcore/formats/kicad/PcbParser.h" +#include "emi/Masks.h" +#include "pdnkit/AnalysisPanel.h" +#include "pi/TargetZ.h" + +int main(int argc, char** argv) { + if (argc < 2) { + std::fprintf(stderr, "usage: consumer_smoke \n"); + return 2; + } + + auto board = + circuitcore::formats::kicad::PcbParser::parse_file(argv[1]); + if (!board) { + std::fprintf(stderr, "parse failed\n"); + return 1; + } + std::printf("parsed: %zu nets, %zu zones\n", board->nets.size(), + board->zones.size()); + if (board->nets.empty()) return 1; + + const pdnkit::pi::TargetZSpec spec{3.3, 0.05, 1.0}; + const double z = pdnkit::pi::target_impedance_flat(spec); + std::printf("target z: %.4f ohm\n", z); + if (std::abs(z - 0.165) > 1e-9) return 1; + + std::printf("consumer smoke ok\n"); + return 0; +} diff --git a/ui/CMakeLists.txt b/ui/CMakeLists.txt index a8ec1ce..6af02e0 100644 --- a/ui/CMakeLists.txt +++ b/ui/CMakeLists.txt @@ -33,7 +33,7 @@ target_include_directories(circuitcore_ui PUBLIC ) # earcut.hpp lives under third_party/ at the repo root (header-only). target_include_directories(circuitcore_ui PRIVATE - ${CMAKE_SOURCE_DIR}/third_party + ${circuitcore_SOURCE_DIR}/third_party ) target_link_libraries(circuitcore_ui