CXX := g++ CXXFLAGS := -std=c++20 -O2 -Wall -Wextra -Wpedantic -pthread -MMD -MP LDFLAGS := -pthread -lrt ORCH_LDFLAGS := $(LDFLAGS) -lusb-1.0 VISA_CXXFLAGS ?= -I/usr/include/ni-visa VISA_LDFLAGS := $(LDFLAGS) -lvisa BUILD_DIR := build BIN_DIR := $(BUILD_DIR)/bin # --- gpr_cpp: vendored C++/CUDA 3D SAR library (originally from VNA_AlGo). # Built automatically by the $(GPR_CPP_LIB) rule below via its own CMake # (build_cmake.sh). CUDA headers and libnvrtc come from the pip nvidia-* # packages inside this repo's venv (same detection as build_cmake.sh); when # those are absent (e.g. Jetson, where CUDA comes with JetPack) the system # toolkit at /usr/local/cuda is used. libcuda is always the system driver. GPR_CPP_DIR ?= data_acq_and_processing/gpr_cpp GPR_CPP_LIB ?= $(GPR_CPP_DIR)/build/libgpr_core_cpp.a # Absolute so the derived -rpath (libnvrtc dir) survives running the binary # from outside the repo root. GPR_VENV ?= $(CURDIR)/.venv GPR_CUDA_INC_DIR ?= $(dir $(firstword $(wildcard $(GPR_VENV)/lib/python*/site-packages/nvidia/*/include/nvrtc.h))) # cuda.h can live in a DIFFERENT pip package than nvrtc.h (Jetson: cuda_runtime # vs cuda_nvrtc); the unified cu13 package on dev machines has both in one dir. GPR_CUDA_RT_INC_DIR ?= $(dir $(firstword $(wildcard $(GPR_VENV)/lib/python*/site-packages/nvidia/*/include/cuda.h))) GPR_NVRTC_LIB ?= $(firstword $(wildcard $(GPR_VENV)/lib/python*/site-packages/nvidia/*/lib/libnvrtc.so*)) # System-CUDA fallback. An empty GPR_CUDA_INC_DIR would also corrupt the compile # command: a bare `-I` swallows the next argument. ifeq ($(strip $(GPR_CUDA_INC_DIR)),) GPR_CUDA_INC_DIR := /usr/local/cuda/include endif ifeq ($(strip $(GPR_CUDA_RT_INC_DIR)),) GPR_CUDA_RT_INC_DIR := /usr/local/cuda/include endif ifeq ($(strip $(GPR_NVRTC_LIB)),) GPR_NVRTC_LIB := $(firstword $(wildcard /usr/local/cuda/lib64/libnvrtc.so*)) endif # Deduplicated CUDA include flags (a single dir on dev machines). GPR_CUDA_INC_FLAGS := $(addprefix -I,$(sort $(GPR_CUDA_INC_DIR) $(GPR_CUDA_RT_INC_DIR))) GPR_CUDA_LIB_DIR := $(dir $(GPR_NVRTC_LIB)) # libnvrtc from pip ships only as libnvrtc.so.N (no .so symlink), so link the # full path; the rpath makes the binary find it without LD_LIBRARY_PATH. DATA_PROCESSOR_LDFLAGS := $(LDFLAGS) $(GPR_CPP_LIB) $(GPR_NVRTC_LIB) -lcuda -Wl,-rpath,$(GPR_CUDA_LIB_DIR) INCLUDES := \ -I$(GPR_CPP_DIR)/include \ $(GPR_CUDA_INC_FLAGS) \ -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/radar/remote_compact_m_k209/remote_compact_m_k209_driver.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/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)) TARGETS := \ $(BIN_DIR)/sweep_orchestrator \ $(BIN_DIR)/data_preprocessor \ $(BIN_DIR)/data_processor .PHONY: all clean kamil_adc_collector sar3d_parity all: $(TARGETS) kamil_adc_collector: $(BIN_DIR)/kamil_adc_collector # On-demand parity check of the sar3d processor against the reference notebook # volumes (scripts/sar3d_volume_compare.py diffs the dumped volume against a # *_volume.npz export). Not part of `all`. SAR3D_PARITY_OBJS := $(addprefix $(BUILD_DIR)/, \ data_acq_and_processing/processing/tools/sar3d_parity_main.o \ data_acq_and_processing/processing/processors/src/sar3d_processor.o \ data_acq_and_processing/common_cpp/config/src/run_config.o \ data_acq_and_processing/common_cpp/ipc/src/shared_types.o) sar3d_parity: $(BIN_DIR)/sar3d_parity $(BIN_DIR)/sar3d_parity: $(SAR3D_PARITY_OBJS) $(GPR_CPP_LIB) @mkdir -p $(BIN_DIR) $(CXX) $(SAR3D_PARITY_OBJS) -o $@ $(DATA_PROCESSOR_LDFLAGS) $(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) $(GPR_CPP_LIB) @mkdir -p $(BIN_DIR) $(CXX) $(DATA_PROCESSOR_OBJS) -o $@ $(DATA_PROCESSOR_LDFLAGS) # Vendored gpr_cpp static lib: delegate to its CMake build (also produces the # standalone_bp example used by sar3d_parity cross-checks). GPR_CPP_SRC_FILES := $(wildcard $(GPR_CPP_DIR)/src/*) $(wildcard $(GPR_CPP_DIR)/include/gpr/*) \ $(wildcard $(GPR_CPP_DIR)/examples/*) $(GPR_CPP_DIR)/CMakeLists.txt $(GPR_CPP_DIR)/build_cmake.sh $(GPR_CPP_LIB): $(GPR_CPP_SRC_FILES) GPR_BUILD_PYTHON=OFF VENV=$(abspath $(GPR_VENV)) bash $(GPR_CPP_DIR)/build_cmake.sh # The collector compiles into its own build/kamil/ tree with collector-only # includes (no VISA), 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) $(VISA_CXXFLAGS) $(INCLUDES) -c $< -o $@ -include $(DEPFILES) clean: rm -rf $(BUILD_DIR) $(GPR_CPP_DIR)/build