project(MsgUtils DESCRIPTION "Message Utilities Library" LANGUAGES CXX ) set(CMAKE_AUTOMOC ON) if(POLICY CMP0167) cmake_policy(SET CMP0167 NEW) endif() find_package(Protobuf REQUIRED) find_package(absl REQUIRED) find_package(Python3 REQUIRED COMPONENTS Interpreter) find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Core) find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Core Network SerialBus) set(MSGUTILS_SCRIPTS_DIR ${CMAKE_SOURCE_DIR}/scripts/MsgUtils) # Create a build-local venv so pip install works on distros that enforce PEP 668 # (Debian/Ubuntu with Python 3.11+, etc.) without polluting system or user site-packages. set(MSGUTILS_VENV_DIR ${CMAKE_CURRENT_BINARY_DIR}/msgutils-venv) set(MSGUTILS_PYTHON ${MSGUTILS_VENV_DIR}/bin/python) # Probe pip inside the venv — a half-created venv missing python3-venv has python but no pip. execute_process( COMMAND ${MSGUTILS_PYTHON} -m pip --version RESULT_VARIABLE _venv_pip_ok OUTPUT_QUIET ERROR_QUIET ) if(NOT _venv_pip_ok EQUAL 0) message(STATUS "Creating msgutils Python venv at ${MSGUTILS_VENV_DIR}") file(REMOVE_RECURSE ${MSGUTILS_VENV_DIR}) execute_process( COMMAND ${Python3_EXECUTABLE} -m venv ${MSGUTILS_VENV_DIR} RESULT_VARIABLE _venv_result OUTPUT_VARIABLE _venv_output ERROR_VARIABLE _venv_output ) if(NOT _venv_result EQUAL 0 OR NOT EXISTS ${MSGUTILS_PYTHON}) message(FATAL_ERROR "Failed to create venv at ${MSGUTILS_VENV_DIR}.\n" "Install the venv module (e.g. 'sudo apt install python3-venv' or 'python3-full' on Debian/Ubuntu, " "matching your Python version).\n" "Output:\n${_venv_output}") endif() # Verify pip is actually usable in the new venv. execute_process( COMMAND ${MSGUTILS_PYTHON} -m pip --version RESULT_VARIABLE _venv_pip_ok OUTPUT_QUIET ERROR_QUIET ) if(NOT _venv_pip_ok EQUAL 0) message(FATAL_ERROR "Venv at ${MSGUTILS_VENV_DIR} was created but pip is not available inside it. " "Install the matching python3-venv package and reconfigure.") endif() endif() include(cmake/MsgUtils.cmake) # Upgrade pip to ensure pyproject.toml-based editable installs are supported (requires pip >= 21.3). execute_process( COMMAND ${MSGUTILS_PYTHON} -m pip install --upgrade pip --quiet RESULT_VARIABLE _pip_upgrade_result ) if(NOT _pip_upgrade_result EQUAL 0) message(FATAL_ERROR "Failed to upgrade pip in msgutils venv (pip returned ${_pip_upgrade_result})") endif() # install the Python package in editable mode so that the generated protobuf files can be imported by the Python scripts # without needing to be copied to the Python package directory execute_process( COMMAND ${MSGUTILS_PYTHON} -m pip install -e ${MSGUTILS_SCRIPTS_DIR} --quiet RESULT_VARIABLE _pip_result ) if(NOT _pip_result EQUAL 0) message(FATAL_ERROR "Failed to install msgutils Python package (pip returned ${_pip_result})") endif() # set(DENALI_MSG_CSV ${CMAKE_CURRENT_SOURCE_DIR}/../../data/FW_Messages_List.csv) set(LEAHI_MSG_CSV ${CMAKE_CURRENT_SOURCE_DIR}/../../data/Leahi_Staging_FW_Messages_List.csv) set(LEAHI_MSG_CONF ${CMAKE_CURRENT_SOURCE_DIR}/../../data/LeahiUnhandled.conf) set(INCLUDES include/AgentMessage.h include/CanMessage.h include/crc.h # include/DenaliLogUtils.h # include/encryption.h include/format.h include/FrameInterface.h include/main.h include/MessageBuilder.h # include/MessageDispatcher.h # include/MessageGlobals.h # include/MessageInterpreter.h # include/qrcodegen.h include/types.h ) set(SRCS src/AgentMessage.cpp src/crc.cpp # src/DenaliLogUtils.cpp # src/encryption.cpp src/format.cpp src/FrameInterface.cpp src/MessageBuilder.cpp # src/MessageDispatcher.cpp # src/MessageInterpreter.cpp # src/qrcodegen.cpp src/types.cpp ) set(GENERATED_INCLUDES # include/DenaliMsgDefs.h # include/DenaliMsgDefs.pb.h include/LeahiMsgDefs.h include/LeahiMsgDefs.pb.h ) set(GENERATED_SRCS # src/DenaliMsgDefs.cpp # src/DenaliMsgDefs.pb.cc src/LeahiMsgDefs.cpp src/LeahiMsgDefs.pb.cc ) # generate_msg_defs_cpp(DENALI_MSG_CSV Denali ${CMAKE_CURRENT_SOURCE_DIR}/include ${CMAKE_CURRENT_SOURCE_DIR}/src denali) # generate_protobuf(DENALI_MSG_CSV DenaliMsgDefs.proto ${CMAKE_CURRENT_BINARY_DIR}/data denali) # generate_protobuf_cpp(DenaliMsgDefs.proto ${CMAKE_CURRENT_BINARY_DIR}/data ${CMAKE_CURRENT_SOURCE_DIR}/include ${CMAKE_CURRENT_SOURCE_DIR}/src) # generate_msg_defs_cpp_csvs(LEAHI_MSG_CSV Leahi ${CMAKE_CURRENT_SOURCE_DIR}/include ${CMAKE_CURRENT_SOURCE_DIR}/src leahi) # generate_protobuf_csvs(LEAHI_MSG_CSV LeahiMsgDefs.proto ${CMAKE_CURRENT_BINARY_DIR}/data leahi) generate_msg_defs_cpp(LEAHI_MSG_CONF Leahi ${CMAKE_CURRENT_SOURCE_DIR}/include ${CMAKE_CURRENT_SOURCE_DIR}/src leahi) generate_protobuf(LEAHI_MSG_CONF LeahiMsgDefs.proto ${CMAKE_CURRENT_BINARY_DIR}/data leahi) generate_protobuf_cpp(LeahiMsgDefs.proto ${CMAKE_CURRENT_BINARY_DIR}/data ${CMAKE_CURRENT_SOURCE_DIR}/include ${CMAKE_CURRENT_SOURCE_DIR}/src) add_library(${PROJECT_NAME} SHARED) target_sources(${PROJECT_NAME} PRIVATE ${INCLUDES} ${GENERATED_INCLUDES} ${SRCS} ${GENERATED_SRCS}) set_target_properties(${PROJECT_NAME} PROPERTIES PUBLIC_HEADER "${INCLUDES}" ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/lib" LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/lib" ADDITIONAL_CLEAN_FILES " \ ${CMAKE_CURRENT_SOURCE_DIR}/bin; \ ${CMAKE_CURRENT_SOURCE_DIR}/lib; \ ${CMAKE_CURRENT_SOURCE_DIR}/cmake; \ ${GENERATED_INCLUDES}; \ ${GENERATED_SRCS} \ " ) target_link_libraries(${PROJECT_NAME} PUBLIC ${Protobuf_LIBRARIES} absl::log absl::log_internal_check_op absl::log_internal_message Qt${QT_VERSION_MAJOR}::Core Qt${QT_VERSION_MAJOR}::Network Qt${QT_VERSION_MAJOR}::SerialBus ) target_include_directories(${PROJECT_NAME} PUBLIC $ ${Protobuf_INCLUDE_DIR} ) file(MAKE_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include ${CMAKE_CURRENT_SOURCE_DIR}/src) install( TARGETS ${PROJECT_NAME} EXPORT ${PROJECT_NAME}Targets PUBLIC_HEADER DESTINATION "${CMAKE_CURRENT_SOURCE_DIR}/include" RUNTIME DESTINATION "${CMAKE_CURRENT_SOURCE_DIR}/bin" ARCHIVE DESTINATION "${CMAKE_CURRENT_SOURCE_DIR}/lib" LIBRARY DESTINATION "${CMAKE_CURRENT_SOURCE_DIR}/lib" COMPONENT dev ) # Add all targets to the build-tree export set export( TARGETS ${PROJECT_NAME} FILE "${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/${PROJECT_NAME}Targets.cmake" ) file(RELATIVE_PATH REL_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/cmake" "${CMAKE_CURRENT_SOURCE_DIR}/include") set(CONF_INCLUDE_DIRS "\${MSGUTILS_CMAKE_DIR}/${REL_INCLUDE_DIR}") # Create the ${PROJECT_NAME}Config.cmake and # ${PROJECT_NAME}ConfigVersion.cmake files ... for the build tree configure_file(${PROJECT_NAME}Config.cmake.in "${CMAKE_CURRENT_SOURCE_DIR}/cmake/${PROJECT_NAME}Config.cmake" @ONLY) configure_file(${PROJECT_NAME}ConfigVersion.cmake.in "${CMAKE_CURRENT_SOURCE_DIR}/cmake/${PROJECT_NAME}ConfigVersion.cmake" @ONLY) # ... for the install tree configure_file(${PROJECT_NAME}Config.cmake.in "${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/${PROJECT_NAME}Config.cmake" @ONLY) configure_file( ${PROJECT_NAME}ConfigVersion.cmake.in "${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/${PROJECT_NAME}ConfigVersion.cmake" @ONLY) # Install the ${PROJECT_NAME}Config.cmake and ${PROJECT_NAME}ConfigVersion.cmake install( FILES "${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/${PROJECT_NAME}Config.cmake" "${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/${PROJECT_NAME}ConfigVersion.cmake" DESTINATION "${CMAKE_CURRENT_SOURCE_DIR}/cmake" ) # Install the export set for use with the install-tree install(EXPORT ${PROJECT_NAME}Targets DESTINATION "${CMAKE_CURRENT_SOURCE_DIR}/cmake")