# SPDX-License-Identifier: GPL-3.0-or-later # SPDX-FileCopyrightText: 2025 ai-ad4 and the FreePDFEditor contributors # spike/CMakeLists.txt # # M0 feasibility spikes (§14). Each spike is its own executable so it can be run # independently and its results reported separately by CI. The spikes link only # against the leaf libraries they exercise (QPDF here), not against Qt. # Find QPDF. System packages (Debian libqpdf-dev) install the config under the # multiarch lib dir; vcpkg installs it under its installed tree. Search both. find_package(QPDF CONFIG QUIET HINTS /usr/lib/${CMAKE_LIBRARY_ARCHITECTURE} /usr/local /usr) # Fall back to a pkg-config probe if the CMake config wasn't installed. if(NOT QPDF_FOUND) find_package(PkgConfig QUIET) if(PkgConfig_FOUND) pkg_check_modules(QPDF libqpdf IMPORTED_TARGET) endif() endif() if(NOT QPDF_FOUND AND NOT TARGET PkgConfig::QPDF) message(STATUS "QPDF not found — Spike A (verbatim round-trip) will not be built. " "Install qpdf (vcpkg, system package, or from source) to enable it.") return() endif() # The QPDF CMake config exports `qpdf::libqpdf` (system packages, e.g. Debian's # libqpdf-dev) and/or `QPDF::qpdf` (vcpkg). pkg-config yields PkgConfig::QPDF. # Accept any of them. if(TARGET qpdf::libqpdf) set(_fpe_qpdf_target qpdf::libqpdf) elseif(TARGET QPDF::qpdf) set(_fpe_qpdf_target QPDF::qpdf) elseif(TARGET PkgConfig::QPDF) set(_fpe_qpdf_target PkgConfig::QPDF) else() message(WARNING "QPDF found but no known imported target — Spike A skipped.") return() endif() add_executable(spike_a_verbatim_roundtrip common/SpikeRunner.cpp common/SpikeRunner.h A_verbatim_roundtrip/main.cpp A_verbatim_roundtrip/Roundtrip.cpp A_verbatim_roundtrip/Roundtrip.h ) target_include_directories(spike_a_verbatim_roundtrip PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) target_link_libraries(spike_a_verbatim_roundtrip PRIVATE ${_fpe_qpdf_target}) target_compile_features(spike_a_verbatim_roundtrip PRIVATE cxx_std_20) freepdfeditor_apply_warnings(spike_a_verbatim_roundtrip) freepdfeditor_apply_hardening(spike_a_verbatim_roundtrip) # --- Spike B: glyph→Unicode + line/paragraph reconstruction (§14 step 5) --- # The reconstruction pipeline (§4.1 steps 2-5) is pure C++ on the synthetic # in-memory model, so it has no third-party dependency for the M0 spike. The # glyph→Unicode step 1 (font cmap / ToUnicode) is exercised separately once # FreeType/HarfBuzz are wired into the production L3 interpreter in M2. add_executable(spike_b_reconstruction common/SpikeRunner.cpp common/SpikeRunner.h B_reconstruction/main.cpp B_reconstruction/Reconstruct.cpp B_reconstruction/Reconstruct.h B_reconstruction/Corpus.cpp B_reconstruction/Corpus.h B_reconstruction/GlyphRun.h ) target_include_directories(spike_b_reconstruction PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) target_compile_features(spike_b_reconstruction PRIVATE cxx_std_20) freepdfeditor_apply_warnings(spike_b_reconstruction) freepdfeditor_apply_hardening(spike_b_reconstruction) # --- Spike C: hb-subset growth of an embedded subset font (§14 step 6) --- # Grow an existing subset font with a new glyph using hb-subset and verify the # result renders via FreeType. §4.2 resolution ladder step 1: when the user # types a character not in the embedded subset, grow the subset from the # installed full font and embed the new subset (never mutating the original). find_package(PkgConfig QUIET) if(PkgConfig_FOUND) pkg_check_modules(HARFBUZZ harfbuzz harfbuzz-subset IMPORTED_TARGET) pkg_check_modules(FREETYPE freetype2 IMPORTED_TARGET) endif() if(TARGET PkgConfig::HARFBUZZ AND TARGET PkgConfig::FREETYPE) add_executable(spike_c_subset_growth common/SpikeRunner.cpp common/SpikeRunner.h C_subset_growth/main.cpp C_subset_growth/SubsetGrowth.cpp C_subset_growth/SubsetGrowth.h ) target_include_directories(spike_c_subset_growth PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) target_link_libraries(spike_c_subset_growth PRIVATE PkgConfig::HARFBUZZ PkgConfig::FREETYPE) target_compile_features(spike_c_subset_growth PRIVATE cxx_std_20) freepdfeditor_apply_warnings(spike_c_subset_growth) freepdfeditor_apply_hardening(spike_c_subset_growth) else() message(STATUS "HarfBuzz/FreeType not found — Spike C (subset growth) will not be " "built. Install libharfbuzz-dev and libfreetype-dev to enable it.") endif() # --- Spike E: sandbox + IPC bring-up (§14 step 8) --- # Two-process model (ADR-0004): a sandboxed document process (seccomp-bpf) and # a UI process, talking over a socketpair via a length-prefixed binary IPC. # This is the one thing the plan says is genuinely painful to retrofit, so it # is de-risked at M0. Linux-only at this stage (seccomp-bpf); macOS App Sandbox # and Windows AppContainer land in M1. # # An earlier version used Cap'n Proto two-party RPC over the socketpair; the # server received and processed requests but the responses never reached the # client — a real integration issue recorded in the spike result doc for M2 to # debug with the full event-loop integration. The raw length-prefixed protocol # measures the channel cost without that blocker. The Cap'n Proto schema # (ipc.capnp) is kept for the M2 RPC work. find_package(PkgConfig QUIET) if(PkgConfig_FOUND) pkg_check_modules(SECCOMP libseccomp IMPORTED_TARGET) endif() if(TARGET PkgConfig::SECCOMP) add_executable(spike_e_sandbox common/SpikeRunner.cpp common/SpikeRunner.h E_sandbox/main.cpp E_sandbox/Sandbox.cpp E_sandbox/Sandbox.h E_sandbox/DocumentProcess.cpp E_sandbox/DocumentProcess.h E_sandbox/UIProcess.cpp E_sandbox/UIProcess.h ) target_include_directories(spike_e_sandbox PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) target_link_libraries(spike_e_sandbox PRIVATE PkgConfig::SECCOMP) target_compile_features(spike_e_sandbox PRIVATE cxx_std_20) freepdfeditor_apply_warnings(spike_e_sandbox) freepdfeditor_apply_hardening(spike_e_sandbox) else() message(STATUS "libseccomp not found — Spike E (sandbox) will not be built. " "Install libseccomp-dev to enable it.") endif()