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

Feature/examples repo #43

Merged
merged 19 commits into from
Aug 21, 2024
Merged
Show file tree
Hide file tree
Changes from 10 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
1 change: 1 addition & 0 deletions .bazelignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
examples
3 changes: 3 additions & 0 deletions .bazelrc
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ build --heap_dump_on_oom
# Speed up all builds by not checking if output files have been modified.
build --noexperimental_check_output_files

# This is a mandatory flag.
build --@rules_python//python/config_settings:python_version=3.10
Copy link
Contributor

Choose a reason for hiding this comment

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

If you add the default = True attribute to the python toolchain in the MODULE file, then you don't need this, right?

Copy link
Owner Author

Choose a reason for hiding this comment

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

Didn't change the toolchain in rules_ros. The flag isn't needed in rules_ros but it's needed in the examples repo.

Copy link
Contributor

Choose a reason for hiding this comment

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

Why is this required in the examples repo?

Copy link
Owner Author

Choose a reason for hiding this comment

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

Otherwise Bazel can't figure out that pip deps are indeed for Python 3.10 toolchain. E.g. I get:

ERROR: /home/user/.cache/bazel/_bazel_user/6e0e647a7496b7382203f7000f7beb27/external/rules_python~~pip~rules_ros_pip_deps/empy/BUILD.bazel:27:6: configurable attribute "actual" in @@rules_python~~pip~rules_ros_pip_deps//empy:pkg doesn't match this configuration: No matching wheel for current configuration's Python version.

The current build configuration's Python version doesn't match any of the Python
wheels available for this wheel. This wheel supports the following Python
configuration settings:
    //_config:is_python_3.10

To determine the current configuration's Python version, run:
    `bazel config <config id>` (shown further below)
and look for
    rules_python//python/config_settings:python_version

If the value is missing, then the "default" Python version is being used,
which has a "null" version value and will not match version constraints.


This instance of @@rules_python~~pip~rules_ros_pip_deps//empy:pkg has configuration identifier aaa66e7. To inspect its configuration, run: bazel config aaa66e7.

For more help, see https://bazel.build/docs/configurable-attributes#faq-select-choose-condition.

ERROR: Analysis of target '//chatter:talker_tests' failed; build aborted: Analysis failed

Copy link
Contributor

Choose a reason for hiding this comment

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

If this is required for the examples repo only, would it make sense to have a .bazelrc for the examples repo only to avoid this for the main repo?

Copy link
Owner Author

Choose a reason for hiding this comment

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

I don't want to maintain two .bazelrc files, that's why I synmlink-ed the rules_ros2 repo one to the examples repo. The flag doesn't harm the main repo.


# Don't bother building targets which aren't dependencies of the tests.
test --build_tests_only

Expand Down
12 changes: 10 additions & 2 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,13 @@ jobs:
image: mvukov/bazel-builder:commit-49178bdf9c151b1fdb1fb0bac580da5d53a990fd
options: --user ${{ needs.configure.outputs.uid_gid }}

# Run bazel test with gcc and clang in each workspace
strategy:
matrix:
folder:
- "."
- "examples"

steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- uses: actions/checkout@v4
Expand All @@ -74,12 +81,13 @@ jobs:
path: |
~/.cache/bazel
~/.cache/bazel-repo
key: v1-bazel-repo-cache-${{ hashFiles('.bazelversion', 'MODULE.bazel', 'repositories/**', 'requirements_lock.txt') }}
restore-keys: v4-bazel-repo-cache
key: v4-bazel-repo-cache-${{ hashFiles('.bazelversion', 'examples/MODULE.bazel', 'repositories/**', 'requirements_lock.txt', 'MODULE.bazel') }}
restore-keys: v4-bazel-repo-cache-
- name: bazel test //...
env:
# Bazelisk will download bazel to here, ensure it is cached between runs.
XDG_CACHE_HOME: /github/home/.cache/bazel-repo
BUILDBUDDY_ORG_API_KEY: ${{ secrets.BUILDBUDDY_ORG_API_KEY }}
USER: ${{ needs.configure.outputs.user_name }}
working-directory: ${{ matrix.folder }}
run: ${GITHUB_WORKSPACE}/.github/workflows/test.sh
30 changes: 0 additions & 30 deletions BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -13,33 +13,3 @@ exports_files([
"requirements.txt",
"requirements_lock.txt",
])

alias(
name = "roscore",
actual = "//third_party/ros/roslaunch:roscore",
)

alias(
name = "rosgraph",
actual = "@ros_comm//:rosgraph",
)

alias(
name = "rosparam",
actual = "@ros_comm//:rosparam",
)

alias(
name = "rosbag_record",
actual = "@ros_comm//:rosbag_record",
)

alias(
name = "rosbag_play",
actual = "@ros_comm//:rosbag_play",
)

alias(
name = "rosservice",
actual = "//third_party/ros/rosservice",
)
10 changes: 3 additions & 7 deletions MODULE.bazel
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
module(
name = "rules_ros",
repo_name = "com_github_mvukov_rules_ros",
)
module(name = "rules_ros")

bazel_dep(name = "bazel_skylib", version = "1.7.1")
bazel_dep(name = "bzip2", version = "1.0.8.bcr.1")
Expand All @@ -13,8 +10,7 @@ bazel_dep(name = "lz4", version = "1.9.4")
bazel_dep(name = "platforms", version = "0.0.10")
bazel_dep(name = "rules_cc", version = "0.0.9")
bazel_dep(name = "rules_foreign_cc", version = "0.11.1")

bazel_dep(name = "rules_python", version = "0.34.0", dev_dependency = True)
bazel_dep(name = "rules_python", version = "0.34.0")

non_module_ros_repositories = use_extension("//ros:extensions.bzl", "non_module_dependencies")
use_repo(
Expand Down Expand Up @@ -64,6 +60,6 @@ pip = use_extension("@rules_python//python/extensions:pip.bzl", "pip")
pip.parse(
hub_name = "rules_ros_pip_deps",
python_version = "3.10",
requirements_lock = "@com_github_mvukov_rules_ros//:requirements_lock.txt",
requirements_lock = "@rules_ros//:requirements_lock.txt",
)
use_repo(pip, "rules_ros_pip_deps")
53 changes: 1 addition & 52 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,58 +20,7 @@ So far a subset of ros-base packages can be built, including support for
- actions, and
- dynamic reconfiguration.

Here is an example.

Let's begin with starting `roscore`:

```sh
bazel run //:roscore
```

In a separate terminal, let's start a (C++) talker node:

```sh
bazel run //examples/chatter:talker
```

This single command will compile and run the talker node.

In a yet another terminal we can start a listener node:

```sh
bazel run //examples/chatter:listener # C++ version or
bazel run //examples/chatter:py_listener # Python version
```

Rosbag recording & playing works as well:

```sh
bazel run //:rosbag_record -- /chatter -o /tmp/foo.bag # to record a bag or
bazel run //:rosbag_play -- /tmp/foo_<timestamp>.bag # to play a bag
```

`rostopic`, tied to this example (see `examples/chatter/BUILD.bazel` for more
info) can be used as

```sh
bazel run //examples/chatter:rostopic -- echo /chatter
```

Not too shabby.

Next, let's start a deployment with the talker and the listener nodes. You can
stop the nodes you started with the above commands. Now execute

```sh
bazel run //examples/chatter:chatter
```

This command will build the necessary nodes and launch them. This is similar
to executing good-ol' `roslaunch`, but, running the chatter `ros_launch` target
using Bazel ensures all necessary dependencies are (re-)built.

In `//examples/dishwasher` you can find another example that demonstrates
defining and usage of ROS actions (and actionlib).
Please take a look at the [examples](examples) folder to get started.

## Background and design decisions

Expand Down
1 change: 1 addition & 0 deletions examples/.bazelrc
29 changes: 29 additions & 0 deletions examples/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
alias(
Copy link
Contributor

Choose a reason for hiding this comment

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

Are these aliases to ensure they are built as I don't see what in the examples depends on them. If so, could be worth adding a comment as to why they're here.

Copy link
Owner Author

Choose a reason for hiding this comment

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

It's more for convenience, referenced some of them in the readme for the chatter examples.

Copy link
Owner Author

Choose a reason for hiding this comment

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

Added docs.

name = "roscore",
actual = "@rules_ros//third_party/ros/roslaunch:roscore",
)

alias(
name = "rosgraph",
actual = "@ros_comm//:rosgraph",
)

alias(
name = "rosparam",
actual = "@ros_comm//:rosparam",
)

alias(
name = "rosbag_record",
actual = "@ros_comm//:rosbag_record",
)

alias(
name = "rosbag_play",
actual = "@ros_comm//:rosbag_play",
)

alias(
name = "rosservice",
actual = "@rules_ros//third_party/ros/rosservice",
)
51 changes: 51 additions & 0 deletions examples/MODULE.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
module(name = "rules_ros_examples")

bazel_dep(name = "rules_python", version = "0.34.0")
Copy link
Contributor

Choose a reason for hiding this comment

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

If you now specify your own python toolchain, wouldn't it be possible to use a different python version?

Copy link
Contributor

Choose a reason for hiding this comment

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

It won't let me reply to the above .bazelrc question but basically because no toolchain is specified as default in the example MODULE.bazel file, you have to specify it as a config flag in the .bazelrc

Copy link
Contributor

Choose a reason for hiding this comment

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

Would it help if we specify a toolchain here?

Copy link
Owner Author

@mvukov mvukov Aug 17, 2024

Choose a reason for hiding this comment

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

If I add the following to examples/MODULE.bazel:

python = use_extension("@rules_python//python/extensions:python.bzl", "python")
python.toolchain(
    is_default = True,
    python_version = "3.10",
)

and remove the config flag from .bazelrc: that works for the examples repo but I get:

DEBUG: /home/user/.cache/bazel/_bazel_user/6e0e647a7496b7382203f7000f7beb27/external/rules_python~/python/private/python.bzl:46:10: WARNING: Ignoring toolchain 'python_3_10' from module 'rules_ros': Toolchain 'python_3_10' from module 'rules_ros_examples' already registered Python version 3.10 and has precedence

IMO, the flag in .bazelrc is a cleaner solution.

Copy link
Contributor

Choose a reason for hiding this comment

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

But isn't this what we want? Being able to override the Python toolchain used?

Copy link
Owner Author

Choose a reason for hiding this comment

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

Didn't have time to investigate how this would work. If you have some time, give it a shot. But, yes, it would be nice if toolchain override could work.

Copy link
Contributor

Choose a reason for hiding this comment

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

Ok fine with me. Let's try that and once it is merged I will try to update in our codebase and report back if there are any errors.


# This import is relevant for these examples and this (rules_ros) repository.
bazel_dep(name = "rules_ros")
local_path_override(
module_name = "rules_ros",
path = "..",
)

# In a normal workflow, you would typically import rules_ros2 into your
mvukov marked this conversation as resolved.
Show resolved Hide resolved
# (mono)repo as follows:
# bazel_dep(name = "rules_ros")
# archive_override(
# module_name = "rules_ros",
# integrity = "sha256-<integrity sum of the .tar.gz archive below>",
# strip_prefix = "rules_ros-<git commit SHA>",
# urls = "https://github.com/mvukov/rules_ros/archive/<git commit SHA>.tar.gz"
# )

non_module_ros_repositories = use_extension("@rules_ros//ros:extensions.bzl", "non_module_dependencies")
use_repo(
non_module_ros_repositories,
"console_bridge",
"orocos_kdl",
"ros_actionlib",
"ros_comm",
"ros_comm_msgs",
"ros_common_msgs",
"ros_dynamic_reconfigure",
"ros_gencpp",
"ros_genmsg",
"ros_genpy",
"ros_geometry2",
"ros_ros",
"ros_std_msgs",
"rosconsole",
"roscpp_core",
"tinyxml",
"urdfdom",
"urdfdom_headers",
)

bazel_dep(name = "rules_boost")
archive_override(
module_name = "rules_boost",
integrity = "sha256-I1iTdF3qckTmDRab+0yjA37Iya9AOGvEGJVoPtfpADM=",
strip_prefix = "rules_boost-42d8155d8f20a1aee8ee20b7903a495bdfb9befd",
urls = "https://github.com/nelhage/rules_boost/archive/42d8155d8f20a1aee8ee20b7903a495bdfb9befd.zip",
)
19 changes: 19 additions & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Examples for rules_ros

This folder provides some examples and guidelines on how you can use this repo
in your very own (mono)repo. It's important to note here that this folder is
a yet another Bazel module (it has a MODULE.bazel file). Please take a look at
the module file to get an idea how to set up yourself.

Besides setting up your module file, please make sure you copy the `.bazelrc`
file as well to your monorepo -- or at least adjust your own using the provided
one.

Before you build/run/test any of the targets in this folder, please make sure
your terminal is in this folder, or in a subfolder, and not in the root
of the repo.

You can start with a simple [chatter](chatter) example.

In `dishwasher` folder you can find another example that demonstrates
defining and usage of ROS actions (and actionlib).
31 changes: 24 additions & 7 deletions examples/chatter/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,17 @@
"""

load("@rules_python//python:defs.bzl", "py_binary")
load("//ros:cc_defs.bzl", "cc_ros_binary")
load("@rules_ros//ros:cc_defs.bzl", "cc_ros_binary")
load(
"//ros:interfaces.bzl",
"@rules_ros//ros:interfaces.bzl",
"cc_ros_interface_library",
"py_ros_interface_library",
"ros_interface_library",
)
load("//ros:launch.bzl", "ros_launch")
load("//ros:test.bzl", "ros_test")
load("//ros:topic.bzl", "ros_topic")
load("@rules_ros//ros:launch.bzl", "ros_launch")
load("@rules_ros//ros:test.bzl", "ros_test")
load("@rules_ros//ros:topic.bzl", "ros_topic")
load("@rules_ros//third_party:expand_template.bzl", "expand_template")

# Handling of ROS messages & services resembles to some extent Bazel's rules for
# handling protobuf messages (e.g. proto_library and cc_proto_library).
Expand Down Expand Up @@ -61,11 +62,27 @@ ros_test(
launch_file = "talker_tests.launch",
nodes = [
":talker",
"//third_party/ros/rostest:advertisetest",
"//third_party/ros/rostest:publishtest",
"@rules_ros//third_party/ros/rostest:advertisetest",
"@rules_ros//third_party/ros/rostest:publishtest",
],
)

expand_template(
name = "talker_tests_launch",
out = "talker_tests.launch",
data = [
":talker",
"@rules_ros//third_party/ros/rostest:advertisetest",
"@rules_ros//third_party/ros/rostest:publishtest",
],
substitutions = {
"{talker}": "$(rootpath :talker)",
"{advertisetest}": "$(rootpath @rules_ros//third_party/ros/rostest:advertisetest)",
"{publishtest}": "$(rootpath @rules_ros//third_party/ros/rostest:publishtest)",
},
template = "talker_tests.launch.tpl",
)

# Defines a C++ listener ROS node.
cc_ros_binary(
name = "listener",
Expand Down
48 changes: 48 additions & 0 deletions examples/chatter/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# A chatter example

Let's begin with starting `roscore`:

```sh
bazel run //:roscore
```

In a separate terminal, let's start a (C++) talker node:

```sh
bazel run //chatter:talker
```

This single command will compile and run the talker node.

In a yet another terminal we can start a listener node:

```sh
bazel run //chatter:listener # C++ version or
bazel run //chatter:py_listener # Python version
```

Rosbag recording & playing works as well:

```sh
bazel run //:rosbag_record -- /chatter -o /tmp/foo.bag # to record a bag or
bazel run //:rosbag_play -- /tmp/foo_<timestamp>.bag # to play a bag
```

`rostopic`, tied to this example (see `BUILD.bazel` for more info) can be used as

```sh
bazel run //chatter:rostopic -- echo /chatter
```

Not too shabby.

Next, let's start a deployment with the talker and the listener nodes. You can
stop the nodes you started with the above commands. Now execute

```sh
bazel run //chatter:chatter
```

This command will build the necessary nodes and launch them. This is similar
to executing good-ol' `roslaunch`, but, running the chatter `ros_launch` target
using Bazel ensures all necessary dependencies are (re-)built.
4 changes: 2 additions & 2 deletions examples/chatter/chatter.launch
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<launch>
<node type="examples/chatter/talker" name="talker" />
<node type="examples/chatter/listener" name="listener" output="screen" />
<node type="chatter/talker" name="talker" />
<node type="chatter/listener" name="listener" output="screen" />
</launch>
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
<launch>
<node name="talker" type="examples/chatter/talker" />
<node name="talker" type="{talker}" />

<test name="advertisetest"
test-name="advertisetest"
type="third_party/ros/rostest/advertisetest">
type="{advertisetest}">
<rosparam>
topics:
- name: /chatter
Expand All @@ -14,7 +14,7 @@

<test name="publishtest"
test-name="publishtest"
type="third_party/ros/rostest/publishtest">
type="{publishtest}">
<rosparam>
topics:
- name: /chatter
Expand Down
Loading