| #------------------------------------------------------------------------------- |
| # Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved. |
| # |
| # SPDX-License-Identifier: BSD-3-Clause |
| # |
| #------------------------------------------------------------------------------- |
| |
| #[===[.rst: |
| NanoPB integration for cmake |
| ---------------------------- |
| |
| This module will: |
| - download nanopb if not available locally |
| - build the runtime static library and the generator |
| - import the static library to the build |
| - define a function to provide access to the generator |
| |
| Note: the python module created by the generator build will be installed under |
| Python_SITELIB ("Third-party platform independent installation directory.") |
| This means the build may alter the state of your system. Please use virtualenv. |
| |
| Note: see requirements.txt for dependencies which need to be installed before |
| running this module. |
| |
| #]===] |
| |
| #### Get the dependency |
| |
| set(NANOPB_URL "https://github.com/nanopb/nanopb.git" |
| CACHE STRING "nanopb repository URL") |
| set(NANOPB_REFSPEC "nanopb-0.4.2" |
| CACHE STRING "nanopb git refspec") |
| set(NANOPB_SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/_deps/nanopb-src" |
| CACHE PATH "nanopb source-code") |
| set(NANOPB_INSTALL_DIR "${CMAKE_CURRENT_BINARY_DIR}/nanopb_install" |
| CACHE PATH "nanopb installation directory") |
| |
| # Checking git |
| find_program(GIT_COMMAND "git") |
| if (NOT GIT_COMMAND) |
| message(FATAL_ERROR "Please install git") |
| endif() |
| |
| set(GIT_OPTIONS |
| GIT_REPOSITORY ${NANOPB_URL} |
| GIT_TAG ${NANOPB_REFSPEC} |
| GIT_SHALLOW FALSE |
| #See the .patch file for details on why it is needed. |
| PATCH_COMMAND git stash |
| COMMAND git apply ${CMAKE_CURRENT_LIST_DIR}/fix-pyhon-name.patch |
| ) |
| |
| if (NOT "${NANOPB_EXTERNAL_INCLUDE_PATHS}" STREQUAL "") |
| string(REPLACE ";" " " NANOPB_EXTERNAL_INCLUDE_PATHS "${NANOPB_EXTERNAL_INCLUDE_PATHS}") |
| endif() |
| |
| include(${TS_ROOT}/tools/cmake/common/LazyFetch.cmake REQUIRED) |
| LazyFetch_MakeAvailable(DEP_NAME nanopb |
| FETCH_OPTIONS ${GIT_OPTIONS} |
| INSTALL_DIR ${NANOPB_INSTALL_DIR} |
| PACKAGE_DIR ${NANOPB_INSTALL_DIR} |
| CACHE_FILE "${TS_ROOT}/external/nanopb/nanopb-init-cache.cmake.in" |
| SOURCE_DIR "${NANOPB_SOURCE_DIR}" |
| ) |
| |
| #set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${NANOPB_INSTALL_DIR}/) |
| |
| #### Build access to the protobuf compiler |
| #TODO: verify protoc dependencies: python3-protobuf |
| find_package(Python3 REQUIRED COMPONENTS Interpreter) |
| |
| find_file(NANOPB_GENERATOR_PATH |
| NAMES nanopb_generator.py |
| PATHS ${nanopb_SOURCE_DIR}/generator |
| DOC "nanopb protobuf compiler" |
| NO_DEFAULT_PATH |
| ) |
| |
| if (NOT NANOPB_GENERATOR_PATH) |
| message(FATAL_ERROR "Nanopb generator was not found!") |
| endif() |
| |
| #[===[.rst: |
| .. cmake:command:: protobuf_generate |
| |
| .. code-block:: cmake |
| |
| protobuf_generate(SRC file.proto |
| TGT foo |
| NAMESPACE bar |
| BASE_DIR "proto/definitions") |
| |
| Run the ``nanopb_generator`` to compile a protobuf definition file into C source. |
| Generated source file will be added to the source list of ``TGT``. Protobuf |
| compilation will take part before TGT+NAMESPACE is built. |
| |
| Protobuf file names added to the same TGT must not collide. |
| |
| Inputs: |
| |
| ``SRC`` |
| Path to of the protobuf file to process. Either absolute or relative to the |
| callers location. |
| |
| ``TGT`` |
| Name of target to compile generated source files. |
| |
| ``NAMESPACE`` |
| Namespace to put generated files under. Specifies include path and allows |
| separating colliding protobuf files. |
| |
| ``BASE_DIR`` |
| Base directory. Generated files are located relative to this base. |
| |
| #]===] |
| function(protobuf_generate) |
| set(_options ) |
| set(_oneValueArgs SRC TGT NAMESPACE BASE_DIR) |
| set(_multiValueArgs ) |
| |
| cmake_parse_arguments(PARAMS "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN}) |
| |
| #Verify mandatory parameters |
| if (NOT DEFINED PARAMS_SRC) |
| message(FATAL_ERROR "nanopb_generate(): mandatory parameter SRC missing.") |
| endif() |
| if (NOT DEFINED PARAMS_TGT) |
| message(FATAL_ERROR "nanopb_generate(): mandatory parameter TGT missing.") |
| endif() |
| if (NOT DEFINED PARAMS_NAMESPACE) |
| message(FATAL_ERROR "nanopb_generate(): mandatory parameter NAMESPACE missing.") |
| endif() |
| if (NOT DEFINED PARAMS_BASE_DIR) |
| message(FATAL_ERROR "nanopb_generate(): mandatory parameter BASE_DIR missing.") |
| endif() |
| |
| #If SRC is not absolute make it relative to the callers location. |
| if (NOT IS_ABSOLUTE ${PARAMS_SRC}) |
| set(PARAMS_SRC "${CMAKE_CURRENT_LIST_DIR}/${PARAMS_SRC}") |
| endif() |
| |
| #Calculate the output directory |
| set(_OUT_DIR_BASE ${CMAKE_BINARY_DIR}/src/${PARAMS_NAMESPACE}) |
| #Calculate output file names |
| get_filename_component(_BASENAME ${PARAMS_SRC} NAME_WE) |
| |
| #Get relative path or SRC to BASE_DIR |
| file(RELATIVE_PATH _SRC_REL ${PARAMS_BASE_DIR} ${PARAMS_SRC}) |
| get_filename_component(_OUT_DIR_REL ${_SRC_REL} DIRECTORY ) |
| |
| #Calculate output file paths |
| set(_OUT_C "${_OUT_DIR_BASE}/${_OUT_DIR_REL}/${_BASENAME}.pb.c") |
| set(_OUT_H "${_OUT_DIR_BASE}/${_OUT_DIR_REL}/${_BASENAME}.pb.h") |
| |
| #some helper variables for the purpose of readability |
| set(_nanopb_target "nanopb_generate_${PARAMS_TGT}_${PARAMS_NAMESPACE}") |
| set(_nanopb_fake_file "nanopb_generate_ff_${PARAMS_TGT}") |
| |
| if (NOT TARGET "${_nanopb_target}") |
| #Tell cmake the dependency (source) file is fake. |
| set_source_files_properties("${_nanopb_fake_file}" PROPERTIES SYMBOLIC "true") |
| #Create a custom target which depends on a "fake" file. |
| add_custom_target("${_nanopb_target}" |
| DEPENDS "${_nanopb_fake_file}") |
| #Add a custom command to the target to create output directory. |
| add_custom_command(OUTPUT "${_nanopb_fake_file}" |
| COMMAND ${CMAKE_COMMAND} -E make_directory ${_OUT_DIR_BASE} |
| COMMENT "Generating source from protobuf definitions for target ${PARAMS_TGT}") |
| #Ensure protobuf build happens before test target. |
| add_dependencies(${PARAMS_TGT} ${_nanopb_target}) |
| #Add include path to protobuf output. |
| target_include_directories(${PARAMS_TGT} PRIVATE ${_OUT_DIR_BASE}) |
| endif() |
| |
| #Append a protobuf generator command to the nanopb_generate target. |
| add_custom_command(OUTPUT "${_OUT_C}" "${_OUT_H}" |
| COMMAND ${Python3_EXECUTABLE} ${NANOPB_GENERATOR_PATH} |
| -I ${PARAMS_BASE_DIR} |
| -D ${_OUT_DIR_BASE} |
| ${_SRC_REL} |
| DEPENDS "${PARAMS_SRC}") |
| |
| #Add generated file to the target |
| set_property(SOURCE "${_OUT_C}" PROPERTY GENERATED TRUE) |
| target_sources(${PARAMS_TGT} PRIVATE "${_OUT_C}") |
| endfunction() |
| |
| #[===[.rst: |
| .. cmake:command:: protobuf_generate_all |
| |
| .. code-block:: cmake |
| |
| protobuf_generate_all(TGT foo |
| NAMESPACE bar |
| BASE_DIR "proto/definitions") |
| |
| Generates C code from all .proto files listed in the target |
| property PROTOBUF_FILES. |
| |
| Inputs: |
| |
| ``TGT`` |
| Name of target to compile generated source files. |
| |
| ``NAMESPACE`` |
| Namespace to put generated files under. Specifies include path and allows |
| separating colliding protobuf files. |
| |
| ``BASE_DIR`` |
| Base directory. Generated files are located relative to this base. |
| |
| #]===] |
| function(protobuf_generate_all) |
| set(_options ) |
| set(_oneValueArgs TGT NAMESPACE BASE_DIR) |
| set(_multiValueArgs ) |
| |
| cmake_parse_arguments(PARAMS "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN}) |
| |
| #Verify mandatory parameters |
| if (NOT DEFINED PARAMS_TGT) |
| message(FATAL_ERROR "nanopb_generate_all(): mandatory parameter TGT missing.") |
| endif() |
| if (NOT DEFINED PARAMS_NAMESPACE) |
| message(FATAL_ERROR "nanopb_generate_all(): mandatory parameter NAMESPACE missing.") |
| endif() |
| if (NOT DEFINED PARAMS_BASE_DIR) |
| message(FATAL_ERROR "nanopb_generate_all(): mandatory parameter BASE_DIR missing.") |
| endif() |
| |
| get_property(_protolist TARGET ${PARAMS_TGT} PROPERTY PROTOBUF_FILES) |
| |
| #Build of each .proto file |
| foreach(_file IN LISTS _protolist) |
| protobuf_generate( |
| TGT ${PARAMS_TGT} |
| SRC "${_file}" |
| NAMESPACE ${PARAMS_NAMESPACE} |
| BASE_DIR ${PARAMS_BASE_DIR}) |
| endforeach() |
| endfunction() |