forked from RobotLocomotion/drake-ros
-
Notifications
You must be signed in to change notification settings - Fork 0
/
ros_cc.bzl
223 lines (201 loc) · 7.77 KB
/
ros_cc.bzl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
# -*- python -*-
load(
"//tools:dload_cc.bzl",
"dload_cc_ldwrap",
"dload_cc_reexec",
)
load(
"//tools:kwargs.bzl",
"filter_to_only_common_kwargs",
"remove_test_specific_kwargs",
)
load(
"//tools:common.bzl",
"incorporate_rmw_implementation",
)
load("//tools:ament_index.bzl", "AmentIndex")
load(
":distro.bzl",
"RUNTIME_ENVIRONMENT",
)
def ros_cc_binary(
name,
rmw_implementation = None,
cc_binary_rule = native.cc_binary,
cc_library_rule = native.cc_library,
shim = "reexec",
**kwargs):
"""
Builds a C/C++ binary and wraps it with a shim that will inject the minimal
runtime environment necessary for execution when depending on targets from
this ROS 2 local repository.
Equivalent to the cc_binary() rule, which this rule decorates.
Args:
name: C/C++ binary target name
rmw_implementation: optional RMW implementation to run against
cc_binary_rule: optional cc_binary() rule override
cc_library_rule: optional cc_library() rule override
shim: optional tactic to use for shimming ("reexec" or "ldwrap")
Additional keyword arguments are forwarded to the `cc_binary_rule`.
The shim tactic of "reexec" will compile two programs: one with the
requested `name` which is just a tiny wrapper that sets environment
variables and then replaces itself with the second program (which has
your actual code). This is the most robust shimming option, with the
downside of having two programs and extra process indirection.
The shim tactic of "ldwrap" will compile just one program, using the linker
flag `--wrap` to insert extra code prior to main(). This has the benefit of
no subprocess indirection, with the following caveats:
* It does not support programs that use the 3-argument form of main,
(where environment variables are passed as a third argument).
* It does not support programs where the main() function is defined in a
cc_library. Always pass the main() function definition in `srcs`.
Note that unit test frameworks often use a library-based main.
"""
# When creating a shared library ("libfoo.so"), don't do anything special.
if kwargs.get("linkshared", False):
native.cc_binary(name = name, **kwargs)
return
# Prepare the list of environment actions.
env_changes = dict(RUNTIME_ENVIRONMENT)
if rmw_implementation:
kwargs, env_changes = \
incorporate_rmw_implementation(
kwargs,
env_changes,
rmw_implementation = rmw_implementation,
)
# Declare an unshimmed, manual binary. For the "reexec" case, this will be
# the program that we reexec into. For the "ldwrap" case, this might still
# be helpful for debugging, but anyway is required to consolidate the
# program's ROS-Bazel aspects into one place.
noshim_name = "_{}_noshim".format(name)
noshim_kwargs = dict(kwargs)
noshim_kwargs.update(visibility = ["//visibility:private"])
noshim_tags = noshim_kwargs.pop("tags", [])
if "manual" not in noshim_tags:
noshim_tags = noshim_tags + ["manual"]
cc_binary_rule(
name = noshim_name,
tags = noshim_tags,
**noshim_kwargs
)
if shim == "reexec":
# Codegen a main function that performs the actions.
main_name_cc = "_{}_reexec_main.cc".format(name)
dload_cc_reexec(
name = main_name_cc,
target = ":" + noshim_name,
env_changes = env_changes,
testonly = kwargs.get("testonly", False),
tags = [
# Only codegen when needed as a dependency.
"manual",
],
visibility = ["//visibility:private"],
)
# Compile it into a binary.
shim_kwargs = filter_to_only_common_kwargs(kwargs)
shim_tags = shim_kwargs.pop("tags", [])
if "nolint" not in shim_tags:
# Don't check generated code.
shim_tags = shim_tags + ["nolint"]
shim_kwargs.update(
srcs = [main_name_cc],
data = [":" + noshim_name],
deps = ["@bazel_ros2_rules//ros2:dload_shim_cc"],
tags = shim_tags,
)
cc_binary_rule(name = name, **shim_kwargs)
elif shim == "ldwrap":
# Codegen a main function that performs the actions.
main_name = "_{}_ldwrap_main".format(name)
main_cc = main_name + ".cc"
dload_cc_ldwrap(
name = main_cc,
target = ":" + noshim_name,
env_changes = env_changes,
testonly = kwargs.get("testonly", False),
tags = [
# Only codegen when needed as a dependency.
"manual",
],
visibility = ["//visibility:private"],
)
# Link the main function into a static library.
main_kwargs = filter_to_only_common_kwargs(kwargs)
main_kwargs.update(visibility = ["//visibility:private"])
main_tags = main_kwargs.pop("tags", [])
if "nolint" not in main_tags:
# Don't check generated code.
main_tags = main_tags + ["nolint"]
cc_library_rule(
name = main_name,
srcs = [main_cc],
linkstatic = True,
deps = ["@bazel_ros2_rules//ros2:dload_shim_cc"],
tags = main_tags,
**main_kwargs
)
# Link the final binary, using the codegen'd main in lieu of the
# original main.
kwargs.update(
deps = kwargs.get("deps", []) + [":" + main_name],
linkopts = kwargs.get("linkopts", []) + ["-Wl,--wrap=main"],
)
cc_binary_rule(name = name, **kwargs)
else:
fail("Unsupported shim=" + str(shim))
def ros_cc_test(
name,
rmw_implementation = None,
cc_binary_rule = native.cc_binary,
cc_library_rule = native.cc_library,
cc_test_rule = native.cc_test,
**kwargs):
"""
Builds a C/C++ test and wraps it with a shim that will inject the minimal
runtime environment necessary for execution when depending on targets from
this ROS 2 local repository.
Equivalent to the cc_test() rule.
Args:
name: C/C++ test target name
rmw_implementation: optional RMW implementation to run against
cc_binary_rule: optional cc_binary() rule override.
cc_library_rule: optional cc_library() rule override (currently unused)
cc_test_rule: optional cc_test() rule override
Additional keyword arguments are forwarded to the `cc_test_rule` and to the
`cc_binary_rule` (minus the test specific ones).
"""
if "shim" in kwargs:
fail("ros_cc_test does not support the shim= option yet.")
noshim_name = "_" + name + "_noshim"
noshim_kwargs = remove_test_specific_kwargs(kwargs)
noshim_kwargs.update(testonly = True)
shim_env_changes = dict(RUNTIME_ENVIRONMENT)
if rmw_implementation:
noshim_kwargs, test_env_changes = \
incorporate_rmw_implementation(
noshim_kwargs,
shim_env_changes,
rmw_implementation = rmw_implementation,
)
cc_binary_rule(
name = noshim_name,
**noshim_kwargs
)
shim_name = "_" + name + "_shim.cc"
shim_kwargs = filter_to_only_common_kwargs(kwargs)
shim_kwargs.update(testonly = True)
dload_cc_reexec(
name = shim_name,
target = ":" + noshim_name,
env_changes = shim_env_changes,
**shim_kwargs
)
kwargs.update(
srcs = [shim_name],
data = [":" + noshim_name],
deps = ["@bazel_ros2_rules//ros2:dload_shim_cc"],
tags = ["nolint"] + kwargs.get("tags", []),
)
cc_test_rule(name = name, **kwargs)