Lin_Simulator/cpp/CMakeLists.txt
Mohamed Salem 251f5d327e Steps 7-8: Master scheduler and end-to-end integration
Step 7 - Master Scheduler (Python + C++):
- QTimer-based schedule execution with start/stop/pause/resume
- Frame sent callback with light-blue visual highlighting
- Mock Rx simulation with incrementing counter data
- Manual send button for individual frame injection
- Global rate spinbox with live update during run
- Schedule table switching

Step 8 - Integration (Python):
- BabyLinBackend wired into MainWindow
- Global rate spinbox live-updates scheduler
- End-to-end tests: load → edit signals → run → Rx arrives → stop
- Edge case tests: no LDF, no selection, double stop
- Full workflow verified with 182 Python tests

Tests: Python 182 | C++ 124

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 17:45:16 +02:00

201 lines
7.2 KiB
CMake

# CMakeLists.txt — Build configuration for the LIN Simulator (C++)
#
# CMAKE BASICS:
# =============
# CMake is a build system generator. It doesn't compile code directly.
# Instead, it generates platform-specific build files:
# - macOS/Linux: Makefiles (then you run `make`)
# - Windows: Visual Studio project files
# - Any platform: Ninja build files (faster than Make)
#
# The workflow is:
# 1. mkdir build && cd build
# 2. cmake .. ← generates build files from this CMakeLists.txt
# 3. cmake --build . ← compiles and links the project
# 4. ./lin_simulator ← run the application
#
# Qt6 integration:
# CMake has built-in support for Qt via find_package(Qt6).
# Qt needs special preprocessing for its features:
# - MOC (Meta-Object Compiler): processes Q_OBJECT macros for signals/slots
# - UIC: compiles .ui designer files to C++ headers (we don't use these)
# - RCC: compiles resource files (icons, etc.) into the binary
cmake_minimum_required(VERSION 3.16)
project(LINSimulator
VERSION 0.1.0
LANGUAGES CXX
DESCRIPTION "LIN Simulator using BabyLIN devices"
)
# C++17 standard — required for structured bindings, std::optional, etc.
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# ── Qt6 auto-processing ──
# These three lines enable Qt's special preprocessors:
# AUTOMOC: automatically runs MOC on headers containing Q_OBJECT
# AUTOUIC: automatically compiles .ui files (if we had any)
# AUTORCC: automatically compiles .qrc resource files
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTORCC ON)
# ── Find Qt6 ──
# find_package searches for Qt6 on the system.
# REQUIRED means CMake will error if Qt6 is not found.
# COMPONENTS lists which Qt modules we need:
# Widgets: GUI widgets (QMainWindow, QPushButton, etc.)
# We'll add SerialPort in Step 5 when we need device communication.
find_package(Qt6 REQUIRED COMPONENTS Widgets SerialPort)
# ── Main application target ──
# qt_add_executable is Qt's wrapper around add_executable.
# It handles platform-specific details (macOS app bundle, Windows subsystem, etc.)
qt_add_executable(lin_simulator
src/main.cpp
src/main_window.cpp
src/main_window.h
src/ldf_parser.cpp
src/ldf_parser.h
src/connection_manager.cpp
src/connection_manager.h
src/scheduler.cpp
src/scheduler.h
)
target_link_libraries(lin_simulator PRIVATE Qt6::Widgets Qt6::SerialPort)
# ── Tests ──
# We use Qt's built-in test framework (QTest) instead of GoogleTest
# because it integrates naturally with Qt's event loop and widgets.
# QTest provides:
# - QVERIFY(condition): assert a condition is true
# - QCOMPARE(actual, expected): assert two values are equal
# - QTest::mouseClick(): simulate mouse events
# - QTest::keyClick(): simulate keyboard events
enable_testing()
find_package(Qt6 REQUIRED COMPONENTS Test)
qt_add_executable(test_main_window
tests/test_main_window.cpp
src/main_window.cpp
src/main_window.h
src/ldf_parser.cpp
src/ldf_parser.h
src/connection_manager.cpp
src/connection_manager.h
src/scheduler.cpp
src/scheduler.h
)
target_link_libraries(test_main_window PRIVATE Qt6::Widgets Qt6::SerialPort Qt6::Test)
target_include_directories(test_main_window PRIVATE src)
add_test(NAME test_main_window COMMAND test_main_window)
# ── Step 2: LDF Parser tests ──
# These test the custom LDF parser (ldf_parser.cpp) in isolation,
# without any GUI. C++ equivalent of python/tests/test_ldf_handler.py.
#
# COMPILE DEFINITIONS:
# target_compile_definitions() injects #define macros at compile time.
# We use it to pass the sample LDF file path to the test code:
#
# CMake: target_compile_definitions(... LDF_SAMPLE_PATH="/absolute/path/sample.ldf")
# Effect: #define LDF_SAMPLE_PATH "/absolute/path/sample.ldf" ← injected into source
# Usage: parseLdf(QString(LDF_SAMPLE_PATH)); ← in test code
#
# This is how C++ projects pass configuration to code at build time.
# Python doesn't need this because it resolves paths at runtime with __file__.
#
# CMAKE_CURRENT_SOURCE_DIR is a built-in CMake variable pointing to the
# directory containing this CMakeLists.txt file (/path/to/cpp/).
set(LDF_SAMPLE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../resources/sample.ldf")
# Parser unit tests — only needs ldf_parser, no main_window
qt_add_executable(test_ldf_parser
tests/test_ldf_parser.cpp
src/ldf_parser.cpp
src/ldf_parser.h
)
target_link_libraries(test_ldf_parser PRIVATE Qt6::Widgets Qt6::SerialPort Qt6::Test)
target_include_directories(test_ldf_parser PRIVATE src)
target_compile_definitions(test_ldf_parser PRIVATE
LDF_SAMPLE_PATH="${LDF_SAMPLE_PATH}"
)
add_test(NAME test_ldf_parser COMMAND test_ldf_parser)
# ── Step 2: LDF Loading GUI integration tests ──
# These test the full pipeline: parse LDF → populate MainWindow tables.
# C++ equivalent of python/tests/test_ldf_loading.py.
#
# This target needs BOTH ldf_parser AND main_window because it tests
# how the GUI responds to loading an LDF file. Each test target in CMake
# is a separate executable — it needs all the source files it depends on.
#
# WHY DUPLICATE SOURCE FILES IN MULTIPLE TARGETS:
# Unlike Python where importing a module shares code, each C++ executable
# is compiled independently. test_ldf_loading needs main_window.cpp because
# it creates MainWindow objects. We could avoid this with a shared library,
# but for a small project, listing sources per target is simpler.
qt_add_executable(test_ldf_loading
tests/test_ldf_loading.cpp
src/main_window.cpp
src/main_window.h
src/ldf_parser.cpp
src/ldf_parser.h
src/connection_manager.cpp
src/connection_manager.h
src/scheduler.cpp
src/scheduler.h
)
target_link_libraries(test_ldf_loading PRIVATE Qt6::Widgets Qt6::SerialPort Qt6::Test)
target_include_directories(test_ldf_loading PRIVATE src)
target_compile_definitions(test_ldf_loading PRIVATE
LDF_SAMPLE_PATH="${LDF_SAMPLE_PATH}"
)
add_test(NAME test_ldf_loading COMMAND test_ldf_loading)
# ── Step 3: Signal editing tests ──
qt_add_executable(test_signal_editing
tests/test_signal_editing.cpp
src/main_window.cpp
src/main_window.h
src/ldf_parser.cpp
src/ldf_parser.h
src/connection_manager.cpp
src/connection_manager.h
src/scheduler.cpp
src/scheduler.h
)
target_link_libraries(test_signal_editing PRIVATE Qt6::Widgets Qt6::SerialPort Qt6::Test)
target_include_directories(test_signal_editing PRIVATE src)
target_compile_definitions(test_signal_editing PRIVATE
LDF_SAMPLE_PATH="${LDF_SAMPLE_PATH}"
)
add_test(NAME test_signal_editing COMMAND test_signal_editing)
# ── Step 4: Rx real-time display tests ──
qt_add_executable(test_rx_realtime
tests/test_rx_realtime.cpp
src/main_window.cpp
src/main_window.h
src/ldf_parser.cpp
src/ldf_parser.h
src/connection_manager.cpp
src/connection_manager.h
src/scheduler.cpp
src/scheduler.h
)
target_link_libraries(test_rx_realtime PRIVATE Qt6::Widgets Qt6::SerialPort Qt6::Test)
target_include_directories(test_rx_realtime PRIVATE src)
target_compile_definitions(test_rx_realtime PRIVATE
LDF_SAMPLE_PATH="${LDF_SAMPLE_PATH}"
)
add_test(NAME test_rx_realtime COMMAND test_rx_realtime)