Skip to content

Commit 3ec62bd

Browse files
davidt315David Tarazi
andauthored
added an EXPORT arg to allow for exporting for other packages to use (#3)
Enables dbc_cpp_gen to exist in a DBC package, then the hpp files can be used by an external package importing the dbc package --------- Co-authored-by: David Tarazi <david@polymathrobotics.com>
1 parent e7748fb commit 3ec62bd

3 files changed

Lines changed: 100 additions & 28 deletions

File tree

Lines changed: 55 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,57 +1,84 @@
11
# SPDX-FileCopyrightText: 2026 Polymath Robotics, Inc.
22
# SPDX-License-Identifier: Apache-2.0
3-
function(generate_dbc_cpp library_name)
3+
#
4+
# generate_dbc_cpp(<library_name> DBC <path/to/file.dbc>)
5+
#
6+
# Generates C/C++ CAN message types from a DBC file and builds them into a static
7+
# library named <library_name> (C++ namespace and C-symbol prefix also <library_name>,
8+
# headers at include/<library_name>/<library_name>.hpp).
9+
#
10+
# The library is ALWAYS installed and exported, so a downstream package that does
11+
# find_package(<this_package>) can link it as the imported target
12+
# <this_package>::<library_name>. Within the generating package it is also usable by
13+
# its plain local name.
14+
#
15+
# NOTE: this is a macro, not a function, on purpose. It calls ament_export_targets()
16+
# and ament_export_dependencies(), whose bookkeeping is stored in ordinary variables
17+
# in the current scope; ament_package() reads them from the package's top-level scope,
18+
# so they must not be trapped inside a function scope.
19+
macro(generate_dbc_cpp library_name)
420
find_package(Python3 REQUIRED COMPONENTS Interpreter)
521

6-
set(one_value_args DBC)
7-
cmake_parse_arguments(ARG "" "${one_value_args}" "" ${ARGN})
8-
if(NOT ARG_DBC)
22+
cmake_parse_arguments(_dbc_arg "" "DBC" "" ${ARGN})
23+
if(NOT _dbc_arg_DBC)
924
message(FATAL_ERROR "generate_dbc_cpp: Missing required keyword argument DBC")
1025
endif()
1126

12-
set(gen_basedir ${CMAKE_CURRENT_BINARY_DIR}/dbc_gen_cpp)
13-
set(gen_dir ${gen_basedir}/${library_name})
27+
set(_dbc_gen_basedir ${CMAKE_CURRENT_BINARY_DIR}/dbc_gen_cpp)
28+
set(_dbc_gen_dir ${_dbc_gen_basedir}/${library_name})
1429

15-
set(generated_c ${gen_dir}/${library_name}.c)
16-
set(generated_h ${gen_dir}/${library_name}.h)
17-
set(generated_hpp ${gen_dir}/${library_name}.hpp)
18-
set(generated_files ${generated_c} ${generated_h} ${generated_hpp})
30+
set(_dbc_generated_c ${_dbc_gen_dir}/${library_name}.c)
31+
set(_dbc_generated_h ${_dbc_gen_dir}/${library_name}.h)
32+
set(_dbc_generated_hpp ${_dbc_gen_dir}/${library_name}.hpp)
1933

20-
# Kind of awkward, but makes the sources get regenerated if the generator tool changes, by depending on the generator sources.
21-
# Finds the python module directory via Python3 import
34+
# Kind of awkward, but makes the sources get regenerated if the generator tool
35+
# changes, by depending on the generator sources. Finds the python module directory.
2236
execute_process(
2337
COMMAND ${Python3_EXECUTABLE} -c "import dbc_gen_cpp, os; print(os.path.dirname(dbc_gen_cpp.__file__))"
24-
OUTPUT_VARIABLE GENERATOR_DIR
38+
OUTPUT_VARIABLE _dbc_generator_dir
2539
OUTPUT_STRIP_TRAILING_WHITESPACE
2640
)
27-
file(GLOB_RECURSE GENERATOR_SOURCES CONFIGURE_DEPENDS
28-
"${GENERATOR_DIR}/*.py"
29-
"${GENERATOR_DIR}/templates/*.j2"
41+
file(GLOB_RECURSE _dbc_generator_sources CONFIGURE_DEPENDS
42+
"${_dbc_generator_dir}/*.py"
43+
"${_dbc_generator_dir}/templates/*.j2"
3044
)
3145

32-
# Generate the source files
46+
# Generate the source files.
3347
add_custom_command(
34-
OUTPUT ${generated_files}
35-
COMMAND ${Python3_EXECUTABLE} -m dbc_gen_cpp ${ARG_DBC} -o ${gen_dir} -n ${library_name}
36-
DEPENDS ${ARG_DBC} ${GENERATOR_SOURCES}
37-
COMMENT "Generating C source from DBC ${ARG_DBC} with cantools"
48+
OUTPUT ${_dbc_generated_c} ${_dbc_generated_h} ${_dbc_generated_hpp}
49+
COMMAND ${Python3_EXECUTABLE} -m dbc_gen_cpp ${_dbc_arg_DBC} -o ${_dbc_gen_dir} -n ${library_name}
50+
DEPENDS ${_dbc_arg_DBC} ${_dbc_generator_sources}
51+
COMMENT "Generating C source from DBC ${_dbc_arg_DBC} with cantools"
3852
VERBATIM
3953
)
4054
add_custom_target(${library_name}_c_sources
41-
DEPENDS ${generated_c} ${generated_h}
55+
DEPENDS ${_dbc_generated_c} ${_dbc_generated_h}
4256
)
4357

44-
# Create the library target from generated sources
45-
add_library(${library_name} STATIC ${generated_c})
58+
# Create the library target from generated sources.
59+
add_library(${library_name} STATIC ${_dbc_generated_c})
4660
add_dependencies(${library_name} ${library_name}_c_sources)
4761
target_link_libraries(${library_name} PUBLIC dbc_gen_cpp::dbc_gen_cpp)
4862
target_include_directories(${library_name}
49-
PUBLIC ${gen_basedir}
63+
PUBLIC
64+
$<BUILD_INTERFACE:${_dbc_gen_basedir}>
65+
$<INSTALL_INTERFACE:include>
5066
)
5167

52-
# Install the generated files to the install space, just in case they're included in public headers
68+
# Install + export the target and its headers so other packages can link it as
69+
# <this_package>::${library_name}.
5370
install(
54-
FILES ${generated_h} ${generated_hpp}
71+
TARGETS ${library_name}
72+
EXPORT ${library_name}Targets
73+
ARCHIVE DESTINATION lib
74+
LIBRARY DESTINATION lib
75+
RUNTIME DESTINATION bin
76+
INCLUDES DESTINATION include
77+
)
78+
install(
79+
FILES ${_dbc_generated_h} ${_dbc_generated_hpp}
5580
DESTINATION include/${library_name}
5681
)
57-
endfunction()
82+
ament_export_targets(${library_name}Targets HAS_LIBRARY_TARGET)
83+
ament_export_dependencies(dbc_gen_cpp)
84+
endmacro()

test_dbc_gen_cpp/CMakeLists.txt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,20 @@ if(BUILD_TESTING)
4848
ENV CATCH_CONFIG_CONSOLE_WIDTH=120
4949
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
5050
)
51+
52+
# Verify that generate_dbc_cpp() installs the generated headers into the export
53+
# location (include/<library_name>/) so downstream packages can consume them.
54+
# This exercises the install/export path, which the compiled test above does not:
55+
# that test links the libraries in-tree via their BUILD_INTERFACE include dirs.
56+
ament_add_test(
57+
test_dbc_exported_headers
58+
GENERATE_RESULT_FOR_RETURN_CODE_ZERO
59+
COMMAND ${CMAKE_COMMAND}
60+
-DINSTALL_PREFIX=${CMAKE_INSTALL_PREFIX}
61+
"-DLIBRARIES=fake_vehicle_can;fake_j1939_can"
62+
-P ${CMAKE_CURRENT_SOURCE_DIR}/test/check_exported_headers.cmake
63+
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
64+
)
5165
endif()
5266

5367
ament_package()
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# SPDX-FileCopyrightText: 2026 Polymath Robotics, Inc.
2+
# SPDX-License-Identifier: Apache-2.0
3+
#
4+
# Verifies that generate_dbc_cpp() exports the generated headers into the install
5+
# space so downstream packages can include them as <library_name>/<library_name>.hpp.
6+
#
7+
# Invoked with -DINSTALL_PREFIX=<prefix> -DLIBRARIES=<lib1;lib2>.
8+
9+
if(NOT DEFINED INSTALL_PREFIX)
10+
message(FATAL_ERROR "check_exported_headers: INSTALL_PREFIX not set")
11+
endif()
12+
if(NOT DEFINED LIBRARIES)
13+
message(FATAL_ERROR "check_exported_headers: LIBRARIES not set")
14+
endif()
15+
16+
set(_missing "")
17+
foreach(_lib IN LISTS LIBRARIES)
18+
foreach(_ext h hpp)
19+
set(_header "${INSTALL_PREFIX}/include/${_lib}/${_lib}.${_ext}")
20+
if(EXISTS "${_header}")
21+
message(STATUS "Found exported header: ${_header}")
22+
else()
23+
message(WARNING "Missing exported header: ${_header}")
24+
list(APPEND _missing "${_header}")
25+
endif()
26+
endforeach()
27+
endforeach()
28+
29+
if(_missing)
30+
message(FATAL_ERROR "generate_dbc_cpp did not export the expected headers:\n ${_missing}")
31+
endif()

0 commit comments

Comments
 (0)