Skip to content
Merged
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
69 changes: 69 additions & 0 deletions .config/clang-format
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
---
# C++ Formatting rules for Polymath Code Standard

# See https://releases.llvm.org/14.0.0/tools/clang/docs/ClangFormatStyleOptions.html for documentation of these options
BasedOnStyle: Google
IndentWidth: 2
ColumnLimit: 120

AccessModifierOffset: -2
AlignAfterOpenBracket: AlwaysBreak
AlignConsecutiveAssignments: None
AlignConsecutiveDeclarations: None
AlignEscapedNewlines: Left
AlignTrailingComments: false
AllowAllArgumentsOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: Empty
AllowShortFunctionsOnASingleLine: false
BinPackArguments: false
BinPackParameters: false
BraceWrapping:
AfterClass: true
AfterControlStatement: MultiLine
AfterEnum: true
AfterFunction: true
AfterNamespace: true
AfterStruct: true
AfterUnion: true
AfterExternBlock: true
BeforeCatch: false
BeforeElse: false
BeforeLambdaBody: false
BeforeWhile: false
IndentBraces: false
SplitEmptyFunction: false
SplitEmptyRecord: false
SplitEmptyNamespace: false
BreakBeforeBraces: Custom
BreakConstructorInitializers: BeforeComma
CompactNamespaces: false
ContinuationIndentWidth: 2
ConstructorInitializerIndentWidth: 0
DerivePointerAlignment: false
EmptyLineAfterAccessModifier: Never
EmptyLineBeforeAccessModifier: LogicalBlock
FixNamespaceComments: true
IncludeBlocks: Regroup
IncludeCategories:
# Headers in <> with .h extension (best guess at C system headers)
- Regex: '<([A-Za-z0-9\Q/-_\E])+\.h>'
Priority: 1
# Headers in <> without extension (C++ system headers)
- Regex: '<([A-Za-z0-9\Q/-_\E])+>'
Priority: 2
# Headers in <> with other extensions.
- Regex: '<([A-Za-z0-9.\Q/-_\E])+>'
Priority: 3
# Headers in ""
- Regex: '"([A-Za-z0-9.\Q/-_\E])+"'
Priority: 4
IndentAccessModifiers: false
IndentPPDirectives: BeforeHash
PackConstructorInitializers: Never
PointerAlignment: Middle
ReferenceAlignment: Middle
ReflowComments: false
SeparateDefinitionBlocks: Always
SortIncludes: CaseInsensitive
SpacesBeforeTrailingComments: 2
13 changes: 13 additions & 0 deletions .config/copyright.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
Copyright (c) 2025-present Polymath Robotics, Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
19 changes: 19 additions & 0 deletions .cpplint.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Because of cpplint's config file assumptions, this can't be contained in .config/ directory
linelength=256

# TODO(emerson) we need to apply a copyright check, maybe not via this tool though
filter=-legal/copyright
# TODO(emerson) we want these, but the style as enforced here is probably not quite right for us
filter=-build/header_guard
filter=-build/c++17

# Per our style guide, we want to allow the use of non-const reference passing for output parameters
filter=-runtime/references

# Disable all formatting checks, this is handled by clang-format
filter=-readability/braces
filter=-whitespace/braces
filter=-whitespace/indent
filter=-whitespace/newline
filter=-whitespace/parens
filter=-whitespace/semicolon
39 changes: 39 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
---
name: Build and test
"on":
pull_request:
push:
branches:
- main

jobs:
build_and_test:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
ros: [humble, jazzy, kilted, rolling]
package: [behaviortree_cpp_pluginlib, behaviortree_cpp_pluginlib_tests]
include:
- ros: humble
ubuntu: jammy
- ros: jazzy
ubuntu: noble
- ros: kilted
ubuntu: noble-testing
- ros: rolling
ubuntu: noble
name: ${{ matrix.ros }} - ${{ matrix.package }}
container:
image: ghcr.io/ros-tooling/setup-ros-docker/setup-ros-docker-ubuntu-${{ matrix.ubuntu }}:latest
steps:
- uses: actions/checkout@v4
- uses: ros-tooling/action-ros-ci@v0.4
with:
target-ros2-distro: ${{ matrix.ros }}
package-name: ${{ matrix.package }}
import-token: ${{ secrets.GITHUB_TOKEN }}
- uses: actions/upload-artifact@v4
with:
name: colcon-logs__${{ matrix.package }}__${{ matrix.ros }}
path: ros_ws/log
16 changes: 16 additions & 0 deletions .github/workflows/pre-commit.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
name: pre-commit
"on":
pull_request:
push:
branches:
- main

jobs:
pre-commit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
- run: sudo apt-get update && sudo apt-get install libxml2-utils
- uses: pre-commit/action@v3.0.1
68 changes: 68 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
---
# See https://pre-commit.com for more information on these settings
repos:
# Generally useful checks provided by pre-commit
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
hooks:
- id: check-added-large-files
- id: check-ast
- id: check-case-conflict
- id: check-merge-conflict
- id: check-shebang-scripts-are-executable
- id: check-symlinks
- id: check-xml
- id: end-of-file-fixer
- id: forbid-submodules
- id: mixed-line-ending
- id: trailing-whitespace
# C++ formatting
- repo: https://github.com/pre-commit/mirrors-clang-format
rev: v19.1.7
hooks:
- id: clang-format
args: ["--style=file:.config/clang-format"]
# C++ linting
- repo: https://github.com/cpplint/cpplint
rev: 2.0.0
hooks:
- id: cpplint
args: ["--config=.cpplint.cfg", --quiet, --output=sed]
# Markdown
- repo: https://github.com/jackdewinter/pymarkdown
rev: v0.9.28
hooks:
- id: pymarkdown
args: [-d, MD013, fix]
# XML
- repo: https://github.com/emersonknapp/ament_xmllint
rev: v0.1
hooks:
- id: ament_xmllint
# CMake
- repo: https://github.com/cmake-lint/cmake-lint
rev: 1.4.3
hooks:
- id: cmakelint
args: [--linelength=140]
# License headers
- repo: https://github.com/Lucas-C/pre-commit-hooks
rev: v1.5.5
hooks:
- id: insert-license
types_or: [cmake]
name: Copyright headers for Python/CMake
args: [
--license-filepath, .config/copyright.txt,
--comment-style, '#',
--allow-past-years,
--no-extra-eol,
]
- id: insert-license
types_or: [c++, c]
name: Copyright headers for C/C++
args: [
--license-filepath, .config/copyright.txt,
--comment-style, '//',
--allow-past-years,
]
20 changes: 20 additions & 0 deletions .ruff.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Python rules for Polymath Code Standard

line-length = 120
indent-width = 4

[format]
preview = true
quote-style = "single"
indent-style = "space"
skip-magic-trailing-comma = false
line-ending = "lf"

[lint]
select = ["E4", "E7", "E9", "F", "I", "PTH"]
# Rules intended for future application
# select = ["N", "D", "C90", "UP", "PERF", "RUF"]
ignore = []
fixable = ["ALL"]
unfixable = []
dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"
11 changes: 10 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,11 @@
# behaviortree_cpp_pluginlib
Pluginlib integration for registering and loading BehaviorTree.CPP extensions automatically

Pluginlib integration for registering and loading BehaviorTree.CPP extensions automatically.

This allows a workflow where any number of BT node plugins can be exposed in a distributed manner, with a single CMake call, so that no centralized plugin-exposure mechanism is needed to be kept updated.

The use of pluginlib enables discovering all these nodes automatic automatically at runtime, without having to provide a list ahead of time to the factory.

The packages in this repository are:
* [behaviortree_cpp_pluginlib](./behaviortree_cpp_pluginlib/) - main implementation, see here for all information
* [behaviortree_cpp_pluginlib_tests](./behaviortree_cpp_pluginlib_tests/) - separated test package to make sure all exposed build-system tools are working as intended for a user
95 changes: 95 additions & 0 deletions behaviortree_cpp_pluginlib/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# Copyright (c) 2025-present Polymath Robotics, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

cmake_minimum_required(VERSION 3.22)
project(behaviortree_cpp_pluginlib)

if(NOT CMAKE_C_STANDARD)
set(CMAKE_C_STANDARD 99)
endif()
if(NOT CMAKE_CXX_STANDARD)
set(CMAKE_CXX_STANDARD 17)
endif()
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
add_compile_options(-Wall -Wextra -Wpedantic)
add_link_options(-Wl,-no-undefined)
endif()

find_package(ament_cmake_auto REQUIRED)
ament_auto_find_build_dependencies()

# Create library
add_library(${PROJECT_NAME} SHARED
src/factory.cpp
)
target_include_directories(${PROJECT_NAME} PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>
)
target_link_libraries(${PROJECT_NAME}
PUBLIC
behaviortree_cpp::behaviortree_cpp
pluginlib::pluginlib
PRIVATE
rcutils::rcutils
)

# Install and export resources
install(
TARGETS ${PROJECT_NAME}
EXPORT ${PROJECT_NAME}_TARGETS
ARCHIVE DESTINATION lib
LIBRARY DESTINATION lib
RUNTIME DESTINATION bin
)
install(
EXPORT ${PROJECT_NAME}_TARGETS
NAMESPACE ${PROJECT_NAME}::
DESTINATION share/${PROJECT_NAME}/cmake
)
install(
FILES src/autoregistrar.cpp.in src/plugin_description.xml.in
DESTINATION share/${PROJECT_NAME}
)
install(
DIRECTORY include/
DESTINATION include
)
install(
DIRECTORY cmake
DESTINATION share/${PROJECT_NAME}
)

if(BUILD_TESTING)
ament_auto_find_test_dependencies()

set(arg_TARGET test_register)
configure_file(
src/autoregistrar.cpp.in
${PROJECT_BINARY_DIR}/test/autoregistrar.cpp
@ONLY
)

ament_add_gtest(test_register
test/test_register.cpp
${PROJECT_BINARY_DIR}/test/autoregistrar.cpp
)
target_link_libraries(test_register ${PROJECT_NAME})
endif()

ament_export_targets(${PROJECT_NAME}_TARGETS HAS_LIBRARY_TARGET)
ament_export_dependencies(behaviortree_cpp pluginlib)
ament_package(
CONFIG_EXTRAS "${PROJECT_NAME}-extras.cmake"
)
21 changes: 21 additions & 0 deletions behaviortree_cpp_pluginlib/DEVELOPING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Implementation Details

## BT Plugin Base Class

[plugin.hpp](./include/behaviortree_cpp_pluginlib/plugin.hpp) defines the abstract base class `BT::BehaviorTreePlugin` which has a no-argument constructor and so can be exposed to `pluginlib`.

Prerequisites for `pluginlib`:
1. Plugins must derive from a known base class and be able to be used polymorphically
1. Plugins must provide a no-argument constructor

## C++ Registration Macros

In [register_macro.hpp](./include/behaviortree_cpp_pluginlib/register_macro.hpp) we provide the macros needed to register an arbitrary number of plugin entrypoints from a single library.

See the doc comments in that file for the breakdown of the implementation.

## CMake Macro

Follow the logic in [register_behaviortree_cpp_plugin.cmake](./cmake/register_behaviortree_cpp_plugin.cmake) for the implementation details. High level:
1. Add `autoregistrar.cpp` to the library target
1. Create `plugin_description.xml` file and register it with the resource index for `pluginlib` to find
Loading
Loading