CXX := g++ PYTHON ?= .venv/bin/python CXXFLAGS := -std=c++20 -O2 -Wall -Wextra -Wpedantic -pthread -MMD -MP LDFLAGS := -pthread -lrt ORCH_LDFLAGS := $(LDFLAGS) -lusb-1.0 BUILD_DIR := build BIN_DIR := $(BUILD_DIR)/bin # --- CUDA for the sar3d processor (optional). Its kernels are compiled at run # time by NVRTC and launched through the CUDA driver API, so no nvcc is needed: # only nvrtc.h, cuda.h, libnvrtc and the NVIDIA driver's libcuda. Headers and # libnvrtc come from the pip nvidia-cuda-* packages in .venv (requirements-cuda.txt, # x86_64) or from a system toolkit in /usr/local/cuda (Jetson). Without them # data_processor still builds; selecting sar3d shows a CUDA warning. CUDA_ROOTS := $(wildcard $(CURDIR)/.venv/lib/python3*/site-packages/nvidia/*) /usr/local/cuda CUDA_NVRTC_HEADER := $(firstword $(wildcard $(addsuffix /include/nvrtc.h,$(CUDA_ROOTS)))) CUDA_DRIVER_HEADER := $(firstword $(wildcard $(addsuffix /include/cuda.h,$(CUDA_ROOTS)))) CUDA_NVRTC_LIB := $(firstword $(wildcard $(addsuffix /lib/libnvrtc.so.*,$(CUDA_ROOTS)) $(addsuffix /lib64/libnvrtc.so.*,$(CUDA_ROOTS)))) CUDA_DRIVER_LIB := $(firstword $(wildcard /usr/lib/*-linux-gnu/libcuda.so.1 /usr/lib/*-linux-gnu/nvidia/libcuda.so.1 /usr/lib64/libcuda.so.1)) ifneq ($(and $(CUDA_NVRTC_HEADER),$(CUDA_DRIVER_HEADER),$(CUDA_NVRTC_LIB),$(CUDA_DRIVER_LIB)),) SAR3D_CXXFLAGS := -DSAR3D_WITH_CUDA $(addprefix -I,$(sort $(dir $(CUDA_NVRTC_HEADER) $(CUDA_DRIVER_HEADER)))) # The rpath lets data_processor find the pip libnvrtc without LD_LIBRARY_PATH. SAR3D_LDFLAGS := $(CUDA_NVRTC_LIB) $(CUDA_DRIVER_LIB) -Wl,-rpath,$(dir $(CUDA_NVRTC_LIB)) endif # Rewritten only when the CUDA setup changes, so installing (or removing) CUDA # rebuilds the sar3d GPU code instead of keeping a stale build. SAR3D_CUDA_STAMP := $(BUILD_DIR)/sar3d_cuda.flags $(shell mkdir -p $(BUILD_DIR) && echo '$(SAR3D_CXXFLAGS) $(SAR3D_LDFLAGS)' | cmp -s - $(SAR3D_CUDA_STAMP) || echo '$(SAR3D_CXXFLAGS) $(SAR3D_LDFLAGS)' > $(SAR3D_CUDA_STAMP)) INCLUDES := \ -Idata_acq_and_processing/common_cpp/ipc/include \ -Idata_acq_and_processing/common_cpp/config/include \ -Idata_acq_and_processing/third_party \ -Idata_acq_and_processing/third_party/eigen \ -Idata_acq_and_processing/sweep_orchestrator/include \ -Idata_acq_and_processing/sweep_orchestrator/device_drivers/interfaces \ -Idata_acq_and_processing/sweep_orchestrator/device_drivers/radar \ -Idata_acq_and_processing/sweep_orchestrator/device_drivers/switches \ -Idata_acq_and_processing/preprocessing/calibration_master/include \ -Idata_acq_and_processing/preprocessing/reference_master/include \ -Idata_acq_and_processing/preprocessing/data_preprocessor/include \ -Idata_acq_and_processing/processing/processors/include \ -Idata_acq_and_processing/processing/data_processor/include \ -Idata_acq_and_processing/processing/locator/include COMMON_SOURCES := \ data_acq_and_processing/common_cpp/ipc/src/shm_ring.cpp \ data_acq_and_processing/common_cpp/ipc/src/shared_types.cpp \ data_acq_and_processing/common_cpp/config/src/run_config.cpp ORCH_SOURCES := \ data_acq_and_processing/sweep_orchestrator/device_drivers/radar/librevna/librevna_minimal_driver_lifecycle.cpp \ data_acq_and_processing/sweep_orchestrator/device_drivers/radar/librevna/librevna_minimal_driver_transport.cpp \ data_acq_and_processing/sweep_orchestrator/device_drivers/radar/librevna/librevna_minimal_driver_protocol.cpp \ data_acq_and_processing/sweep_orchestrator/device_drivers/switches/h7992_minimal_driver.cpp \ data_acq_and_processing/sweep_orchestrator/device_drivers/switches/hmc349a_minimal_driver.cpp \ data_acq_and_processing/sweep_orchestrator/src/sweep_orchestrator.cpp \ data_acq_and_processing/sweep_orchestrator/src/main.cpp PREPROC_SOURCES := \ data_acq_and_processing/preprocessing/calibration_master/src/calibration_master.cpp \ data_acq_and_processing/preprocessing/calibration_master/src/channel_bundle_support.cpp \ data_acq_and_processing/preprocessing/calibration_master/src/through_calibrator.cpp \ data_acq_and_processing/preprocessing/reference_master/src/reference_master.cpp \ data_acq_and_processing/preprocessing/data_preprocessor/src/data_preprocessor.cpp \ data_acq_and_processing/preprocessing/data_preprocessor/src/main.cpp LOCATOR_SOURCES := \ data_acq_and_processing/processing/locator/src/payload_builder.cpp \ data_acq_and_processing/processing/locator/src/tcp_server.cpp PROCESSOR_SOURCES := \ data_acq_and_processing/processing/processors/src/bscan_processor.cpp \ data_acq_and_processing/processing/processors/src/gpr_processor.cpp \ data_acq_and_processing/processing/processors/src/passthrough_processor.cpp \ data_acq_and_processing/processing/processors/src/sar3d_processor.cpp \ data_acq_and_processing/processing/processors/src/sar3d_gpu.cpp \ data_acq_and_processing/processing/data_processor/src/processing_live_config.cpp \ data_acq_and_processing/processing/data_processor/src/data_processor.cpp \ data_acq_and_processing/processing/data_processor/src/main.cpp \ $(LOCATOR_SOURCES) # Kamil ADC collector: standalone L-Card E-502 acquisition binary. It loads the # proprietary libx502api/libe502api at runtime via dlopen, so it builds anywhere # from the vendored headers alone and only needs those libraries present at run # time. Built on demand (not part of `all`) for radar.model == kamil_adc. KAMIL_COLLECTOR_DIR := data_acq_and_processing/kamil_adc_collector # The collector now also drives the RF switches itself (switch-aware mode), so it # reuses the orchestrator's switch drivers and the shared run_config loader, which # pull in the common config/ipc/locator headers and the vendored nlohmann/json. KAMIL_COLLECTOR_INCLUDES := \ -I$(KAMIL_COLLECTOR_DIR)/include \ -I$(KAMIL_COLLECTOR_DIR)/vendor/lcard \ -Idata_acq_and_processing/common_cpp/ipc/include \ -Idata_acq_and_processing/common_cpp/config/include \ -Idata_acq_and_processing/sweep_orchestrator/device_drivers/interfaces \ -Idata_acq_and_processing/sweep_orchestrator/device_drivers/switches \ -Idata_acq_and_processing/processing/locator/include \ -Idata_acq_and_processing/third_party KAMIL_COLLECTOR_LDFLAGS := -pthread -ldl -lutil # Collector sources, including the shared drivers/config loader it reuses. These # are compiled into a private build/kamil/ tree (see rule below) so they never # collide with the orchestrator's objects, which use different compile flags. KAMIL_COLLECTOR_SOURCES := \ $(KAMIL_COLLECTOR_DIR)/src/main.cpp \ $(KAMIL_COLLECTOR_DIR)/src/tty_protocol_writer.cpp \ $(KAMIL_COLLECTOR_DIR)/src/capture_file_writer.cpp \ data_acq_and_processing/common_cpp/config/src/run_config.cpp \ data_acq_and_processing/common_cpp/ipc/src/shared_types.cpp \ data_acq_and_processing/sweep_orchestrator/device_drivers/switches/h7992_minimal_driver.cpp \ data_acq_and_processing/sweep_orchestrator/device_drivers/switches/hmc349a_minimal_driver.cpp SWEEP_ORCH_OBJS := $(addprefix $(BUILD_DIR)/,$(COMMON_SOURCES:.cpp=.o) $(ORCH_SOURCES:.cpp=.o)) PREPROCESSOR_OBJS := $(addprefix $(BUILD_DIR)/,$(COMMON_SOURCES:.cpp=.o) $(PREPROC_SOURCES:.cpp=.o)) DATA_PROCESSOR_OBJS := $(addprefix $(BUILD_DIR)/,$(COMMON_SOURCES:.cpp=.o) $(PROCESSOR_SOURCES:.cpp=.o)) KAMIL_BUILD_DIR := $(BUILD_DIR)/kamil KAMIL_COLLECTOR_OBJS := $(addprefix $(KAMIL_BUILD_DIR)/,$(notdir $(KAMIL_COLLECTOR_SOURCES:.cpp=.o))) DEPFILES := $(sort $(SWEEP_ORCH_OBJS:.o=.d) $(PREPROCESSOR_OBJS:.o=.d) $(DATA_PROCESSOR_OBJS:.o=.d) $(KAMIL_COLLECTOR_OBJS:.o=.d)) NATIVE_TEST_SOURCES := $(COMMON_SOURCES) $(LOCATOR_SOURCES) \ data_acq_and_processing/tests/native_regressions.cpp \ data_acq_and_processing/processing/data_processor/src/processing_live_config.cpp \ data_acq_and_processing/preprocessing/calibration_master/src/channel_bundle_support.cpp \ data_acq_and_processing/sweep_orchestrator/src/sweep_orchestrator.cpp \ $(KAMIL_COLLECTOR_DIR)/src/capture_file_writer.cpp \ $(KAMIL_COLLECTOR_DIR)/src/tty_protocol_writer.cpp NATIVE_BUILD_DIR := $(BUILD_DIR)/native_tests NATIVE_TEST_OBJS := $(addprefix $(NATIVE_BUILD_DIR)/,$(NATIVE_TEST_SOURCES:.cpp=.o)) NATIVE_CXXFLAGS := $(CXXFLAGS) -O1 -g $(if $(NATIVE_SANITIZERS),-fsanitize=$(NATIVE_SANITIZERS) -fno-omit-frame-pointer) NATIVE_FLAGS_STAMP := $(NATIVE_BUILD_DIR)/compiler.flags $(shell mkdir -p $(NATIVE_BUILD_DIR) && echo '$(NATIVE_CXXFLAGS)' | cmp -s - $(NATIVE_FLAGS_STAMP) || echo '$(NATIVE_CXXFLAGS)' > $(NATIVE_FLAGS_STAMP)) DEPFILES += $(NATIVE_TEST_OBJS:.o=.d) TARGETS := \ $(BIN_DIR)/sweep_orchestrator \ $(BIN_DIR)/data_preprocessor \ $(BIN_DIR)/data_processor .PHONY: all clean kamil_adc_collector check-native check-sar3d all: $(TARGETS) kamil_adc_collector: $(BIN_DIR)/kamil_adc_collector check-native: $(NATIVE_BUILD_DIR)/native_regressions $(NATIVE_BUILD_DIR)/native_regressions run_config_examples/run_config_simulator.example.json SAR3D_TEST_SOURCES := data_acq_and_processing/tests/sar3d_fixture.cpp \ data_acq_and_processing/processing/processors/src/sar3d_processor.cpp \ data_acq_and_processing/processing/processors/src/sar3d_gpu.cpp SAR3D_TEST_OBJS := $(addprefix $(NATIVE_BUILD_DIR)/,$(SAR3D_TEST_SOURCES:.cpp=.o)) SAR3D_EMULATION_OBJ := $(NATIVE_BUILD_DIR)/data_acq_and_processing/tests/sar3d_kernel_emulation.o SAR3D_KERNEL_TEST_OBJ := $(NATIVE_BUILD_DIR)/data_acq_and_processing/tests/sar3d_kernel_regressions.o SAR3D_EMULATION_HEADERS := $(NATIVE_BUILD_DIR)/sar3d_kernels.inc $(NATIVE_BUILD_DIR)/sar3d_helpers.inc DEPFILES += $(SAR3D_TEST_OBJS:.o=.d) $(SAR3D_EMULATION_OBJ:.o=.d) $(SAR3D_KERNEL_TEST_OBJ:.o=.d) check-sar3d: $(NATIVE_BUILD_DIR)/sar3d_fixture $(NATIVE_BUILD_DIR)/sar3d_math_fixture $(NATIVE_BUILD_DIR)/sar3d_kernel_regressions $(NATIVE_BUILD_DIR)/sar3d_kernel_regressions $(PYTHON) data_acq_and_processing/tests/test_sar3d_oracle.py $(NATIVE_BUILD_DIR)/sar3d_fixture: $(SAR3D_TEST_OBJS) $(CXX) $(NATIVE_CXXFLAGS) $^ -o $@ $(LDFLAGS) $(SAR3D_LDFLAGS) $(NATIVE_BUILD_DIR)/sar3d_math_fixture: $(filter-out $(NATIVE_BUILD_DIR)/data_acq_and_processing/processing/processors/src/sar3d_gpu.o,$(SAR3D_TEST_OBJS)) $(SAR3D_EMULATION_OBJ) $(CXX) $(NATIVE_CXXFLAGS) $^ -o $@ $(LDFLAGS) $(NATIVE_BUILD_DIR)/sar3d_kernel_regressions: $(SAR3D_KERNEL_TEST_OBJ) $(SAR3D_EMULATION_OBJ) $(CXX) $(NATIVE_CXXFLAGS) $^ -o $@ $(LDFLAGS) $(SAR3D_EMULATION_HEADERS) &: data_acq_and_processing/tests/generate_sar3d_emulation.py data_acq_and_processing/processing/processors/src/sar3d_gpu.cpp data_acq_and_processing/processing/processors/src/sar3d_gpu.hpp $(PYTHON) data_acq_and_processing/tests/generate_sar3d_emulation.py $(NATIVE_BUILD_DIR) $(SAR3D_EMULATION_OBJ): NATIVE_CXXFLAGS += -I$(NATIVE_BUILD_DIR) $(SAR3D_EMULATION_OBJ): $(SAR3D_EMULATION_HEADERS) $(NATIVE_BUILD_DIR)/data_acq_and_processing/processing/processors/src/sar3d_gpu.o: NATIVE_CXXFLAGS += $(SAR3D_CXXFLAGS) $(NATIVE_BUILD_DIR)/data_acq_and_processing/processing/processors/src/sar3d_gpu.o: $(SAR3D_CUDA_STAMP) $(NATIVE_BUILD_DIR)/native_regressions: $(NATIVE_TEST_OBJS) $(CXX) $(NATIVE_CXXFLAGS) $^ -o $@ $(LDFLAGS) -lutil $(NATIVE_BUILD_DIR)/%.o: %.cpp $(NATIVE_FLAGS_STAMP) @mkdir -p $(dir $@) $(CXX) $(NATIVE_CXXFLAGS) $(INCLUDES) -I$(KAMIL_COLLECTOR_DIR)/include -c $< -o $@ $(BIN_DIR)/sweep_orchestrator: $(SWEEP_ORCH_OBJS) @mkdir -p $(BIN_DIR) $(CXX) $(SWEEP_ORCH_OBJS) -o $@ $(ORCH_LDFLAGS) $(BIN_DIR)/data_preprocessor: $(PREPROCESSOR_OBJS) @mkdir -p $(BIN_DIR) $(CXX) $(PREPROCESSOR_OBJS) -o $@ $(LDFLAGS) $(BIN_DIR)/data_processor: $(DATA_PROCESSOR_OBJS) $(SAR3D_CUDA_STAMP) @mkdir -p $(BIN_DIR) $(CXX) $(DATA_PROCESSOR_OBJS) -o $@ $(LDFLAGS) $(SAR3D_LDFLAGS) $(if $(SAR3D_LDFLAGS),,@echo "note: CUDA not found, selecting sar3d will show a warning") $(BUILD_DIR)/data_acq_and_processing/processing/processors/src/sar3d_gpu.o: CXXFLAGS += $(SAR3D_CXXFLAGS) $(BUILD_DIR)/data_acq_and_processing/processing/processors/src/sar3d_gpu.o: $(SAR3D_CUDA_STAMP) # The collector compiles into its own build/kamil/ tree with collector-only # includes, so the shared driver/config sources it reuses never collide # with the orchestrator's objects of the same name. Basenames are unique, so a # vpath lets one pattern rule find every source. vpath %.cpp $(sort $(dir $(KAMIL_COLLECTOR_SOURCES))) $(KAMIL_BUILD_DIR)/%.o: %.cpp @mkdir -p $(dir $@) $(CXX) $(CXXFLAGS) $(KAMIL_COLLECTOR_INCLUDES) -c $< -o $@ $(BIN_DIR)/kamil_adc_collector: $(KAMIL_COLLECTOR_OBJS) @mkdir -p $(BIN_DIR) $(CXX) $(KAMIL_COLLECTOR_OBJS) -o $@ $(KAMIL_COLLECTOR_LDFLAGS) $(BUILD_DIR)/%.o: %.cpp @mkdir -p $(dir $@) $(CXX) $(CXXFLAGS) $(INCLUDES) -c $< -o $@ -include $(DEPFILES) clean: rm -rf $(BUILD_DIR)