Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generate messages in downstream builds #338

Closed
wants to merge 9 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,14 @@ find_package(gz-cmake3 REQUIRED)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

gz_configure_project(VERSION_SUFFIX)
gz_configure_project(VERSION_SUFFIX
CONFIG_EXTRAS "gz-msgs-extras.cmake.in")

# Install cmake support files
install(
DIRECTORY cmake/
DESTINATION "lib/cmake/${PROJECT_NAME}"
)

if (UNIX AND NOT APPLE)
set (EXTRA_TEST_LIB_DEPS stdc++fs)
Expand Down Expand Up @@ -73,6 +80,11 @@ gz_find_package(GzProtobuf
COMPONENTS all
PRETTY Protobuf)

#--------------------------------------
# Find gz-utils
gz_find_package(gz-utils2 REQUIRED)
set(GZ_UTILS_VER ${gz-utils2_VERSION_MAJOR})

#--------------------------------------
# Find gz-math
gz_find_package(gz-math7 REQUIRED)
Expand All @@ -92,7 +104,7 @@ gz_find_package(TINYXML2 REQUIRED PRIVATE PRETTY tinyxml2)
#============================================================================
# Configure the build
#============================================================================
gz_configure_build(QUIT_IF_BUILD_ERRORS)
gz_configure_build(QUIT_IF_BUILD_ERRORS COMPONENTS compiled)

#============================================================================
# gz command line support
Expand Down
77 changes: 77 additions & 0 deletions cmake/gz_msgs_factory.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
##################################################
# A function that calls protoc on a protobuf file
# Options:
# One value arguments:
# FACTORY_GEN_SCRIPT - Location of the factory generator script
# PROTO_PACKAGE - Protobuf package the file belongs to (e.g. ".gz.msgs")
# PROTOC_EXEC - Path to protoc
# INPUT_PROTO - Path to the input .proto file
# OUTPUT_CPP_DIR - Path where C++ files are saved
# OUTPUT_INCLUDES - A CMake variable name containing a list that the C++ header path should be appended to
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# OUTPUT_INCLUDES - A CMake variable name containing a list that the C++ header path should be appended to
# OUTPUT_INCLUDES - A CMake variable name containing a list that the C++ include path should be appended to

# OUTPUT_CPP_HH_VAR - A CMake variable name containing a list that the C++ header path should be appended to
# OUTPUT_CPP_CC_VAR - A Cmake variable name containing a list that the C++ source path should be appended to
# Multi value arguments
# INPUT_PROTOS - Passed to protoc --proto_path
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

indent comment

# PROTO_PATH - Passed to protoc --proto_path
function(gz_msgs_factory)
set(options "")
set(oneValueArgs
FACTORY_GEN_SCRIPT
PROTO_PACKAGE
OUTPUT_CPP_DIR
OUTPUT_CPP_HH_VAR
OUTPUT_CPP_CC_VAR)
set(multiValueArgs INPUT_PROTOS PROTO_PATH)

cmake_parse_arguments(gz_msgs_factory "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})

set(proto_package_dir ".")
if(gz_msgs_factory_PROTO_PACKAGE)
string(REPLACE "." "/" proto_package_dir ${gz_msgs_factory_PROTO_PACKAGE})
endif()

set(output_header "${gz_msgs_factory_OUTPUT_CPP_DIR}/${proto_package_dir}/MessageTypes.hh")
set(output_source "${gz_msgs_factory_OUTPUT_CPP_DIR}/${proto_package_dir}/register.cc")

list(APPEND ${gz_msgs_factory_OUTPUT_CPP_HH_VAR} ${output_header})
list(APPEND ${gz_msgs_factory_OUTPUT_CPP_CC_VAR} ${output_source})

list(APPEND output_files ${output_header})
list(APPEND output_files ${output_source})

set(${gz_msgs_factory_OUTPUT_CPP_HH_VAR} ${${gz_msgs_factory_OUTPUT_CPP_HH_VAR}} PARENT_SCOPE)
set(${gz_msgs_factory_OUTPUT_CPP_CC_VAR} ${${gz_msgs_factory_OUTPUT_CPP_CC_VAR}} PARENT_SCOPE)

set(depends_index)

# Full path to an index file, which contains all defined message types for that proto file
foreach(proto_file ${generate_messages_MSGS_PROTOS})
get_filename_component(FIL_WE ${proto_file} NAME_WE)
string(REPLACE "." "_" PACKAGE_UNDER ${gz_msgs_factory_PROTO_PACKAGE})
string(REPLACE "." "_" MESSAGE_UNDER ${FIL_WE})
set(input_index "${gz_msgs_factory_OUTPUT_CPP_DIR}/${PACKAGE_UNDER}_${MESSAGE_UNDER}.pb_index")
list(APPEND depends_index ${input_index})
endforeach()


set(GENERATE_ARGS
Comment on lines +54 to +57
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
endforeach()
set(GENERATE_ARGS
endforeach()
set(GENERATE_ARGS

--output-cpp-path "${gz_msgs_factory_OUTPUT_CPP_DIR}"
--proto-package "${gz_msgs_factory_PROTO_PACKAGE}"
--proto-path "${gz_msgs_factory_PROTO_PATH}"
--protos "${gz_msgs_factory_INPUT_PROTOS}"
)

add_custom_command(
OUTPUT ${output_files}
COMMAND Python3::Interpreter
ARGS ${gz_msgs_factory_FACTORY_GEN_SCRIPT} ${GENERATE_ARGS}
DEPENDS
${depends_index}
Comment on lines +68 to +69
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style

Suggested change
DEPENDS
${depends_index}
DEPENDS ${depends_index}

# While the script is executed in the source directory, it does not write
# to the source tree. All outputs are stored in the build directory.
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
COMMENT "Running factory generator"
VERBATIM
)

endfunction()
107 changes: 107 additions & 0 deletions cmake/gz_msgs_protoc.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
##################################################
# A function that calls protoc on a protobuf file
# Options:
# GENERATE_CPP - generates c++ code for the message if specified
# One value arguments:
# PROTO_PACKAGE - Protobuf package the file belongs to (e.g. ".gz.msgs")
# PROTOC_EXEC - Path to protoc
# INPUT_PROTO - Path to the input .proto file
# OUTPUT_CPP_DIR - Path where C++ files are saved
# OUTPUT_INCLUDES - A CMake variable name containing a list that the C++ header path should be appended to
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# OUTPUT_INCLUDES - A CMake variable name containing a list that the C++ header path should be appended to
# OUTPUT_INCLUDES - A CMake variable name containing a list that the C++ include path should be appended to

# OUTPUT_CPP_HH_VAR - A CMake variable name containing a list that the C++ header path should be appended to
# OUTPUT_CPP_CC_VAR - A Cmake variable name containing a list that the C++ source path should be appended to
# Multi value arguments
# PROTO_PATH - Passed to protoc --proto_path
function(gz_msgs_protoc)
set(options GENERATE_CPP)
set(oneValueArgs
MSGS_GEN_SCRIPT
PROTO_PACKAGE
PROTOC_EXEC
GZ_PROTOC_PLUGIN
INPUT_PROTO
OUTPUT_CPP_DIR
OUTPUT_INCLUDES
OUTPUT_CPP_HH_VAR
OUTPUT_DETAIL_CPP_HH_VAR
OUTPUT_CPP_CC_VAR)
set(multiValueArgs PROTO_PATH DEPENDENCY_PROTO_PATHS)

cmake_parse_arguments(gz_msgs_protoc "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})

get_filename_component(ABS_FIL ${gz_msgs_protoc_INPUT_PROTO} ABSOLUTE)
get_filename_component(FIL_WE ${gz_msgs_protoc_INPUT_PROTO} NAME_WE)

set(protoc_args)
set(output_files)

set(proto_package_dir ".")
if(gz_msgs_protoc_PROTO_PACKAGE)
string(REPLACE "." "/" proto_package_dir ${gz_msgs_protoc_PROTO_PACKAGE})
endif()

if(gz_msgs_protoc_GENERATE_CPP)
# Full path to generated header (${PROJECT_BINARY_DIR}/include/gz/msgs/foo.pb.h)
set(output_header "${gz_msgs_protoc_OUTPUT_CPP_DIR}/${proto_package_dir}/${FIL_WE}.pb.h")
# Full path to generated detail header (${PROJECT_BINARY_DIR}/include/gz/msgs/details/foo.pb.h)
set(output_detail_header "${gz_msgs_protoc_OUTPUT_CPP_DIR}/${proto_package_dir}/details/${FIL_WE}.pb.h")
# Full path to generated ignition header (${PROJECT_BINARY_DIR}/include/foo.pb.cc)
set(output_source "${gz_msgs_protoc_OUTPUT_CPP_DIR}/${proto_package_dir}/${FIL_WE}.pb.cc")

# Full path to an index file, which contains all defined message types for that proto file
string(REPLACE "." "_" PACKAGE_UNDER ${gz_msgs_protoc_PROTO_PACKAGE})
string(REPLACE "." "_" MESSAGE_UNDER ${FIL_WE})
set(output_index "${gz_msgs_protoc_OUTPUT_CPP_DIR}/${PACKAGE_UNDER}_${MESSAGE_UNDER}.pb_index")

# Generate a clean relative path (gz/msgs/foo.pb.h)
string(REPLACE "${PROJECT_BINARY_DIR}/include/" "" output_include ${output_header})
list(APPEND ${gz_msgs_protoc_OUTPUT_INCLUDES} "${output_include}")

list(APPEND ${gz_msgs_protoc_OUTPUT_CPP_HH_VAR} ${output_header})
list(APPEND ${gz_msgs_protoc_OUTPUT_CPP_CC_VAR} ${output_source})
list(APPEND ${gz_msgs_protoc_OUTPUT_DETAIL_CPP_HH_VAR} ${output_detail_header})

list(APPEND output_files ${output_header})
list(APPEND output_files ${output_detail_header})
list(APPEND output_files ${output_source})
list(APPEND output_files ${output_index})

set(${gz_msgs_protoc_OUTPUT_INCLUDES} ${${gz_msgs_protoc_OUTPUT_INCLUDES}} PARENT_SCOPE)
set(${gz_msgs_protoc_OUTPUT_DETAIL_CPP_HH_VAR} ${${gz_msgs_protoc_OUTPUT_DETAIL_CPP_HH_VAR}} PARENT_SCOPE)
set(${gz_msgs_protoc_OUTPUT_CPP_HH_VAR} ${${gz_msgs_protoc_OUTPUT_CPP_HH_VAR}} PARENT_SCOPE)
set(${gz_msgs_protoc_OUTPUT_CPP_CC_VAR} ${${gz_msgs_protoc_OUTPUT_CPP_CC_VAR}} PARENT_SCOPE)
endif()

set(GENERATE_ARGS
--protoc-exec "$<TARGET_FILE:${gz_msgs_protoc_PROTOC_EXEC}>"
--gz-generator-bin "${gz_msgs_protoc_GZ_PROTOC_PLUGIN}"
--proto-path "${gz_msgs_protoc_PROTO_PATH}"
--input-path "${ABS_FIL}"
)

if(gz_msgs_protoc_DEPENDENCY_PROTO_PATHS)
list(APPEND GENERATE_ARGS
--dependency-proto-paths "${gz_msgs_protoc_DEPENDENCY_PROTO_PATHS}"
)
endif()

if(${gz_msgs_protoc_GENERATE_CPP})
list(APPEND GENERATE_ARGS
--generate-cpp
--output-cpp-path "${gz_msgs_protoc_OUTPUT_CPP_DIR}")
endif()
Comment on lines +88 to +92
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style

Suggested change
if(${gz_msgs_protoc_GENERATE_CPP})
list(APPEND GENERATE_ARGS
--generate-cpp
--output-cpp-path "${gz_msgs_protoc_OUTPUT_CPP_DIR}")
endif()
if(${gz_msgs_protoc_GENERATE_CPP})
list(APPEND GENERATE_ARGS
--generate-cpp
--output-cpp-path "${gz_msgs_protoc_OUTPUT_CPP_DIR}"
)
endif()


add_custom_command(
OUTPUT ${output_files}
COMMAND Python3::Interpreter
ARGS ${gz_msgs_protoc_MSGS_GEN_SCRIPT} ${GENERATE_ARGS}
DEPENDS
${ABS_FIL}
Comment on lines +98 to +99
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style

Suggested change
DEPENDS
${ABS_FIL}
DEPENDS ${ABS_FIL}

# While the script is executed in the source directory, it does not write
# to the source tree. All outputs are stored in the build directory.
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
COMMENT "Running protoc on ${gz_msgs_protoc_INPUT_PROTO}"
VERBATIM
)

endfunction()
5 changes: 5 additions & 0 deletions compiled/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
gz_get_libsources_and_unittests(sources tests)

add_subdirectory(include/gz/msgs)

#gz_add_component(compiled SOURCES ${sources})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove?

1 change: 1 addition & 0 deletions compiled/include/gz/msgs/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
gz_install_all_headers()
Empty file.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
41 changes: 41 additions & 0 deletions core/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Build a custom protoc plugin
##################################################
gz_add_executable(${PROJECT_NAME}_protoc_plugin
${CMAKE_CURRENT_SOURCE_DIR}/generator/Generator.cc
${CMAKE_CURRENT_SOURCE_DIR}/generator/generator_main.cc)
target_link_libraries(${PROJECT_NAME}_protoc_plugin
protobuf::libprotoc
protobuf::libprotobuf)
target_include_directories(${PROJECT_NAME}_protoc_plugin PRIVATE ${PROTOBUF_INCLUDE_DIR})
target_compile_features(${PROJECT_NAME}_protoc_plugin PRIVATE ${GZ_CXX_11_FEATURES})

if (UNIX)
target_link_libraries(${PROJECT_NAME}_protoc_plugin pthread)
endif()

install(
TARGETS ${PROJECT_NAME}_protoc_plugin
DESTINATION ${GZ_BIN_INSTALL_DIR})


gz_get_libsources_and_unittests(sources tests)
Comment on lines +18 to +21
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
DESTINATION ${GZ_BIN_INSTALL_DIR})
gz_get_libsources_and_unittests(sources tests)
DESTINATION ${GZ_BIN_INSTALL_DIR})
gz_get_libsources_and_unittests(sources tests)


# Create the library target
gz_create_core_library(
SOURCES ${sources}
${CMAKE_CURRENT_SOURCE_DIR}/src/DynamicFactory.cc
${CMAKE_CURRENT_SOURCE_DIR}/src/MessageFactory.cc
)

target_link_libraries(${PROJECT_LIBRARY_TARGET_NAME}
PUBLIC
protobuf::libprotobuf
gz-utils${GZ_UTILS_VER}::gz-utils${GZ_UTILS_VER}
)

# Build the unit tests
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove?

#gz_build_tests(
# TYPE UNIT
# SOURCES ${tests})

add_subdirectory(include/gz/msgs)
39 changes: 9 additions & 30 deletions src/Generator.cc → core/generator/Generator.cc
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include <algorithm>
#include <filesystem>
#include <iostream>
#include <fstream>
#include <map>
#include <memory>
#include <sstream>
Expand Down Expand Up @@ -89,6 +90,7 @@ bool Generator::Generate(const FileDescriptor *_file,
auto parent_path = filePath.parent_path();
auto fileStem = filePath.stem().string();


// protoc generates ignition/msgs/msg.pb.cc and ignition/msgs/msg.pb.hh
// This generator injects code into the msg.pb.cc file, but generates
// a completely new header that wraps the original protobuf header
Expand All @@ -112,6 +114,10 @@ bool Generator::Generate(const FileDescriptor *_file,
newHeaderFilename += part.string() + "/";
sourceFilename += part.string() + "/";
}

auto message_type_index = _generatorContext->Open(identifier + fileStem + ".pb_index");
io::Printer index_printer(message_type_index, '$');

identifier += fileStem;
headerFilename += fileStem + ".gz.h";
newHeaderFilename += "details/" + fileStem + ".pb.h";
Expand All @@ -136,15 +142,7 @@ bool Generator::Generate(const FileDescriptor *_file,

#include <memory>

#include <gz/msgs/Export.hh>

#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable: 4100 4512 4127 4068 4244 4267 4251 4146)
#endif

#include <$detail_header$>

)");

auto ns = getNamespaces(_file->package());
Expand All @@ -157,6 +155,9 @@ bool Generator::Generate(const FileDescriptor *_file,
auto desc = _file->message_type(i);
std::string ptrTypes;

index_printer.PrintRaw(desc->name());
index_printer.PrintRaw("\n");

// Define std::unique_ptr types for our messages
ptrTypes += "typedef std::unique_ptr<"
+ desc->name() + "> "
Expand Down Expand Up @@ -185,33 +186,11 @@ bool Generator::Generate(const FileDescriptor *_file,
printer.PrintRaw("} // namespace " + *name + "\n");
}

printer.PrintRaw("#ifdef _MSC_VER\n");
printer.PrintRaw("#pragma warning(pop)\n");
printer.PrintRaw("#endif\n");
printer.PrintRaw("\n");

printer.Print(variables, "#endif // $define_guard$\n");
}

// Inject code in the auto-generated source files immediately following
// the #include <google/protobuf*.h> calls.
{
std::unique_ptr<io::ZeroCopyOutputStream> output(
_generatorContext->OpenForInsert(sourceFilename, "includes"));
io::Printer printer(output.get(), '$');

// Add the gz-msgs Factory header
printer.Print("#include \"gz/msgs/Factory.hh\"\n", "name",
"includes");

for (auto i = 0; i < _file->message_type_count(); ++i)
{
std::string factory = "GZ_REGISTER_STATIC_MSG(\"gz_msgs.";
factory += _file->message_type(i)->name() + "\", " +
_file->message_type(i)->name() +")\n";
printer.Print(factory.c_str(), "name", "includes");
}
}
return true;
}
}
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
1 change: 1 addition & 0 deletions core/include/gz/msgs/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
gz_install_all_headers()
Loading