diff --git a/examples/cmake_relpath/CMakeLists.txt b/examples/cmake_relpath/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..e7727d8546599117afdbe5efcd26064b37f9bbfc --- /dev/null +++ b/examples/cmake_relpath/CMakeLists.txt @@ -0,0 +1,18 @@ +cmake_minimum_required(VERSION 2.8) +project(NANOPB_CMAKE_SIMPLE C) + +set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../../extra) +find_package(Nanopb REQUIRED) +include_directories(${NANOPB_INCLUDE_DIRS}) + +nanopb_generate_cpp(PROTO_SRCS PROTO_HDRS RELPATH proto + proto/simple.proto proto/sub/unlucky.proto) + +include_directories(${CMAKE_CURRENT_BINARY_DIR}) +#add_custom_target(generate_proto_sources DEPENDS ${PROTO_SRCS} ${PROTO_HDRS}) +set_source_files_properties(${PROTO_SRCS} ${PROTO_HDRS} + PROPERTIES GENERATED TRUE) + +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Werror -g -O0") + +add_executable(simple simple.c ${PROTO_SRCS} ${PROTO_HDRS}) diff --git a/examples/cmake_relpath/README.txt b/examples/cmake_relpath/README.txt new file mode 100644 index 0000000000000000000000000000000000000000..aa0f3f3a771766d9328c5ed20068caa78ec4c4ab --- /dev/null +++ b/examples/cmake_relpath/README.txt @@ -0,0 +1,18 @@ +Nanopb example "simple" using CMake +======================= + +This example is the same as the simple nanopb example but built using CMake. + +Example usage +------------- + +On Linux, create a build directory and then call cmake: + + nanopb/examples/cmake_simple$ mkdir build + nanopb/examples/cmake_simple$ cd build/ + nanopb/examples/cmake_simple/build$ cmake .. + nanopb/examples/cmake_simple/build$ make + +After that, you can run it with the command: ./simple + +On other platforms supported by CMake, refer to CMake instructions. diff --git a/examples/cmake_relpath/proto/simple.proto b/examples/cmake_relpath/proto/simple.proto new file mode 100644 index 0000000000000000000000000000000000000000..3bf4ad1def6da42d9cbd203a0aee9c1e00b992cb --- /dev/null +++ b/examples/cmake_relpath/proto/simple.proto @@ -0,0 +1,11 @@ +// A very simple protocol definition, consisting of only +// one message. +syntax = "proto2"; + +import "sub/unlucky.proto"; + +message SimpleMessage { + required int32 lucky_number = 1; + required UnluckyNumber unlucky = 2; +} + diff --git a/examples/cmake_relpath/proto/sub/unlucky.proto b/examples/cmake_relpath/proto/sub/unlucky.proto new file mode 100644 index 0000000000000000000000000000000000000000..97a42c9cde0532d2fb5f6fb20375c3823f4755e1 --- /dev/null +++ b/examples/cmake_relpath/proto/sub/unlucky.proto @@ -0,0 +1,5 @@ +syntax = "proto2"; + +message UnluckyNumber { + required uint32 number = 1; +} diff --git a/examples/cmake_relpath/simple.c b/examples/cmake_relpath/simple.c new file mode 100644 index 0000000000000000000000000000000000000000..231886c28b746cdda07acf4b349d34f5ab5127a8 --- /dev/null +++ b/examples/cmake_relpath/simple.c @@ -0,0 +1,73 @@ +#include <stdio.h> +#include <pb_encode.h> +#include <pb_decode.h> +#include "simple.pb.h" + +int main() +{ + /* This is the buffer where we will store our message. */ + uint8_t buffer[128]; + size_t message_length; + bool status; + + /* Encode our message */ + { + /* Allocate space on the stack to store the message data. + * + * Nanopb generates simple struct definitions for all the messages. + * - check out the contents of simple.pb.h! + * It is a good idea to always initialize your structures + * so that you do not have garbage data from RAM in there. + */ + SimpleMessage message = SimpleMessage_init_zero; + + /* Create a stream that will write to our buffer. */ + pb_ostream_t stream = pb_ostream_from_buffer(buffer, sizeof(buffer)); + + /* Fill in the lucky number */ + message.lucky_number = 13; + message.unlucky.number = 42; + + /* Now we are ready to encode the message! */ + status = pb_encode(&stream, SimpleMessage_fields, &message); + message_length = stream.bytes_written; + + /* Then just check for any errors.. */ + if (!status) + { + printf("Encoding failed: %s\n", PB_GET_ERROR(&stream)); + return 1; + } + } + + /* Now we could transmit the message over network, store it in a file or + * wrap it to a pigeon's leg. + */ + + /* But because we are lazy, we will just decode it immediately. */ + + { + /* Allocate space for the decoded message. */ + SimpleMessage message = SimpleMessage_init_zero; + + /* Create a stream that reads from the buffer. */ + pb_istream_t stream = pb_istream_from_buffer(buffer, message_length); + + /* Now we are ready to decode the message. */ + status = pb_decode(&stream, SimpleMessage_fields, &message); + + /* Check for errors... */ + if (!status) + { + printf("Decoding failed: %s\n", PB_GET_ERROR(&stream)); + return 1; + } + + /* Print the data contained in the message. */ + printf("Your lucky number was %d!\n", message.lucky_number); + printf("Your unlucky number was %u!\n", message.unlucky.number); + } + + return 0; +} + diff --git a/extra/FindNanopb.cmake b/extra/FindNanopb.cmake index 749999d197b974c577e5a63d0beb7defc1aeebec..dda63f63441f1fd66e3236a0a7ac0d66fb19ccae 100644 --- a/extra/FindNanopb.cmake +++ b/extra/FindNanopb.cmake @@ -28,17 +28,22 @@ # ==================================================================== # # NANOPB_GENERATE_CPP (public function) -# SRCS = Variable to define with autogenerated -# source files -# HDRS = Variable to define with autogenerated -# header files -# ARGN = proto files +# NANOPB_GENERTAE_CPP(SRCS HDRS [RELPATH <root-path-of-proto-files>] +# <proto-files>...) +# SRCS = Variable to define with autogenerated source files +# HDRS = Variable to define with autogenerated header files +# If you want to use relative paths in your import statements use the RELPATH +# option. The argument to RELPATH should be the directory that all the +# imports will be relative to. +# When RELPATH is not specified then all proto files can be imported without +# a path. +# # # ==================================================================== # Example: # # set(NANOPB_SRC_ROOT_FOLDER "/path/to/nanopb") -# set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${NANOPB_SRC_ROOT_FOLDER}/cmake) +# set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${NANOPB_SRC_ROOT_FOLDER}/extra) # find_package( Nanopb REQUIRED ) # include_directories(${NANOPB_INCLUDE_DIRS}) # @@ -47,6 +52,19 @@ # include_directories(${CMAKE_CURRENT_BINARY_DIR}) # add_executable(bar bar.cc ${PROTO_SRCS} ${PROTO_HDRS}) # +# Example with RELPATH: +# Assume we have a layout like: +# .../CMakeLists.txt +# .../bar.cc +# .../proto/ +# .../proto/foo.proto (Which contains: import "sub/bar.proto"; ) +# .../proto/sub/bar.proto +# Everything would be the same as the previous example, but the call to +# NANOPB_GENERATE_CPP would change to: +# +# NANOPB_GENERATE_CPP(PROTO_SRCS PROTO_HDRS RELPATH proto +# proto/foo.proto proto/sub/bar.proto) +# # ==================================================================== #============================================================================= @@ -92,35 +110,35 @@ function(NANOPB_GENERATE_CPP SRCS HDRS) - if(NOT ARGN) + cmake_parse_arguments(NANOPB_GENERATE_CPP "" "RELPATH" "" ${ARGN}) + if(NOT NANOPB_GENERATE_CPP_UNPARSED_ARGUMENTS) return() endif() if(NANOPB_GENERATE_CPP_APPEND_PATH) # Create an include path for each file specified - foreach(FIL ${ARGN}) + foreach(FIL ${NANOPB_GENERATE_CPP_UNPARSED_ARGUMENTS}) get_filename_component(ABS_FIL ${FIL} ABSOLUTE) get_filename_component(ABS_PATH ${ABS_FIL} PATH) - - list(FIND _nanobp_include_path ${ABS_PATH} _contains_already) - if(${_contains_already} EQUAL -1) - list(APPEND _nanobp_include_path -I ${ABS_PATH}) - endif() + list(APPEND _nanobp_include_path "-I${ABS_PATH}") endforeach() else() - set(_nanobp_include_path -I ${CMAKE_CURRENT_SOURCE_DIR}) + set(_nanobp_include_path "-I${CMAKE_CURRENT_SOURCE_DIR}") + endif() + + if(NANOPB_GENERATE_CPP_RELPATH) + list(APPEND _nanobp_include_path "-I${NANOPB_GENERATE_CPP_RELPATH}") endif() if(DEFINED NANOPB_IMPORT_DIRS) foreach(DIR ${NANOPB_IMPORT_DIRS}) get_filename_component(ABS_PATH ${DIR} ABSOLUTE) - list(FIND _nanobp_include_path ${ABS_PATH} _contains_already) - if(${_contains_already} EQUAL -1) - list(APPEND _nanobp_include_path -I ${ABS_PATH}) - endif() + list(APPEND _nanobp_include_path -I ${ABS_PATH}) endforeach() endif() + list(REMOVE_DUPLICATES _nanobp_include_path) + set(${SRCS}) set(${HDRS}) @@ -162,10 +180,27 @@ function(NANOPB_GENERATE_CPP SRCS HDRS) VERBATIM) endforeach() - foreach(FIL ${ARGN}) + if(NANOPB_GENERATE_CPP_RELPATH) + get_filename_component(ABS_ROOT ${NANOPB_GENERATE_CPP_RELPATH} ABSOLUTE) + endif() + foreach(FIL ${NANOPB_GENERATE_CPP_UNPARSED_ARGUMENTS}) get_filename_component(ABS_FIL ${FIL} ABSOLUTE) get_filename_component(FIL_WE ${FIL} NAME_WE) get_filename_component(FIL_DIR ${FIL} PATH) + set(FIL_PATH_REL) + if(ABS_ROOT) + # Check that the file is under the given "RELPATH" + string(FIND ${ABS_FIL} ${ABS_ROOT} LOC) + if (${LOC} EQUAL 0) + string(REPLACE "${ABS_ROOT}/" "" FIL_REL ${ABS_FIL}) + get_filename_component(FIL_PATH_REL ${FIL_REL} PATH) + file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${FIL_PATH_REL}) + endif() + endif() + if(NOT FIL_PATH_REL) + set(FIL_PATH_REL ".") + endif() + set(NANOPB_OPTIONS_FILE ${FIL_DIR}/${FIL_WE}.options) set(NANOPB_OPTIONS) if(EXISTS ${NANOPB_OPTIONS_FILE}) @@ -174,26 +209,28 @@ function(NANOPB_GENERATE_CPP SRCS HDRS) set(NANOPB_OPTIONS_FILE) endif() - list(APPEND ${SRCS} "${CMAKE_CURRENT_BINARY_DIR}/${FIL_WE}.pb.c") - list(APPEND ${HDRS} "${CMAKE_CURRENT_BINARY_DIR}/${FIL_WE}.pb.h") + set(GEN_C_FILE ) + + list(APPEND ${SRCS} "${CMAKE_CURRENT_BINARY_DIR}/${FIL_PATH_REL}/${FIL_WE}.pb.c") + list(APPEND ${HDRS} "${CMAKE_CURRENT_BINARY_DIR}/${FIL_PATH_REL}/${FIL_WE}.pb.h") add_custom_command( - OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${FIL_WE}.pb" + OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${FIL_PATH_REL}/${FIL_WE}.pb" COMMAND ${PROTOBUF_PROTOC_EXECUTABLE} ARGS -I${GENERATOR_PATH} -I${GENERATOR_CORE_DIR} -I${CMAKE_CURRENT_BINARY_DIR} ${_nanobp_include_path} - -o${FIL_WE}.pb ${ABS_FIL} + -o${FIL_PATH_REL}/${FIL_WE}.pb ${ABS_FIL} DEPENDS ${ABS_FIL} ${GENERATOR_CORE_PYTHON_SRC} COMMENT "Running C++ protocol buffer compiler on ${FIL}" VERBATIM ) add_custom_command( - OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${FIL_WE}.pb.c" - "${CMAKE_CURRENT_BINARY_DIR}/${FIL_WE}.pb.h" + OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${FIL_PATH_REL}/${FIL_WE}.pb.c" + "${CMAKE_CURRENT_BINARY_DIR}/${FIL_PATH_REL}/${FIL_WE}.pb.h" COMMAND ${PYTHON_EXECUTABLE} - ARGS ${NANOPB_GENERATOR_EXECUTABLE} ${FIL_WE}.pb ${NANOPB_OPTIONS} - DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/${FIL_WE}.pb" ${NANOPB_OPTIONS_FILE} - COMMENT "Running nanopb generator on ${FIL_WE}.pb" + ARGS ${NANOPB_GENERATOR_EXECUTABLE} ${FIL_PATH_REL}/${FIL_WE}.pb ${NANOPB_OPTIONS} + DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/${FIL_PATH_REL}/${FIL_WE}.pb" ${NANOPB_OPTIONS_FILE} + COMMENT "Running nanopb generator on ${FIL_PATH_REL}/${FIL_WE}.pb" VERBATIM ) endforeach()