@@ -7,7 +7,9 @@ CmakeInfo = provider(
7
7
"hdrs" : "" ,
8
8
"srcs" : "" ,
9
9
"deps" : "" ,
10
+ "system_includes" : "" ,
10
11
"includes" : "" ,
12
+ "quote_includes" : "" ,
11
13
"stripped_includes" : "" ,
12
14
"imported_static_libs" : "" ,
13
15
"imported_dynamic_libs" : "" ,
@@ -45,6 +47,10 @@ def _file_kind(file):
45
47
return "dynamic_lib"
46
48
return None
47
49
50
+ def _get_includes (includes ):
51
+ # see strip prefix comment below to understand why we are skipping virtual includes here
52
+ return [_cmake_path (i ) for i in includes .to_list () if "/_virtual_includes/" not in i ]
53
+
48
54
def _cmake_aspect_impl (target , ctx ):
49
55
if not ctx .rule .kind .startswith ("cc_" ):
50
56
return [CmakeInfo (name = None , transitive_deps = depset ())]
@@ -82,18 +88,17 @@ def _cmake_aspect_impl(target, ctx):
82
88
linkopts += [ctx .expand_make_variables ("linkopts" , o , {}) for o in ctx .rule .attr .linkopts ]
83
89
84
90
compilation_ctx = target [CcInfo ].compilation_context
85
- includes = compilation_ctx .system_includes .to_list ()
86
- includes += compilation_ctx .includes .to_list ()
87
- includes += compilation_ctx .quote_includes .to_list ()
88
- includes += [opt [2 :] for opt in copts if opt .startswith ("-I" )]
91
+ system_includes = _get_includes (compilation_ctx .system_includes )
92
+
93
+ # move -I copts to includes
94
+ includes = _get_includes (compilation_ctx .includes ) + [_cmake_path (opt [2 :]) for opt in copts if opt .startswith ("-I" )]
95
+ copts = [opt for opt in copts if not opt .startswith ("-I" )]
96
+ quote_includes = _get_includes (compilation_ctx .quote_includes )
89
97
90
98
# strip prefix is special, as in bazel it creates a _virtual_includes directory with symlinks
91
99
# as we want to avoid relying on bazel having done that, we must undo that mechanism
92
100
# also for some reason cmake fails to propagate these with target_include_directories,
93
101
# so we propagate them ourselvels by using the stripped_includes field
94
- # also, including '.' on macOS creates a conflict between a `version` file at the root of the
95
- # workspace and a standard library, so we skip that (and hardcode an `-iquote .` in setup.cmake)
96
- includes = [_cmake_path (i ) for i in includes if not ("/_virtual_includes/" in i or (is_macos and i == "." ))]
97
102
stripped_includes = []
98
103
if getattr (ctx .rule .attr , "strip_include_prefix" , "" ):
99
104
prefix = ctx .rule .attr .strip_include_prefix .strip ("/" )
@@ -108,7 +113,6 @@ def _cmake_aspect_impl(target, ctx):
108
113
"${BAZEL_EXEC_ROOT}/%s/%s" % (ctx .var ["BINDIR" ], prefix ), # generated
109
114
]
110
115
111
- copts = [opt for opt in copts if not opt .startswith ("-I" )]
112
116
deps = [dep [CmakeInfo ] for dep in deps if CmakeInfo in dep ]
113
117
114
118
# by the book this should be done with depsets, but so far the performance implication is negligible
@@ -127,6 +131,8 @@ def _cmake_aspect_impl(target, ctx):
127
131
srcs = srcs ,
128
132
deps = [dep for dep in deps if dep .name != None ],
129
133
includes = includes ,
134
+ system_includes = system_includes ,
135
+ quote_includes = quote_includes ,
130
136
stripped_includes = stripped_includes ,
131
137
imported_static_libs = static_libs ,
132
138
imported_dynamic_libs = dynamic_libs ,
@@ -145,7 +151,7 @@ cmake_aspect = aspect(
145
151
fragments = ["cpp" ],
146
152
)
147
153
148
- def _map_cmake_info (info ):
154
+ def _map_cmake_info (info , is_windows ):
149
155
args = " " .join ([info .name , info .modifier ] + info .hdrs + info .srcs ).strip ()
150
156
commands = [
151
157
"add_%s(%s)" % (info .kind , args ),
@@ -180,6 +186,19 @@ def _map_cmake_info(info):
180
186
commands += [
181
187
"target_include_directories(%s %s %s)" % (info .name , info .modifier or "PUBLIC" , " " .join (info .includes )),
182
188
]
189
+ if info .system_includes :
190
+ commands += [
191
+ "target_include_directories(%s SYSTEM %s %s)" % (info .name , info .modifier or "PUBLIC" , " " .join (info .system_includes )),
192
+ ]
193
+ if info .quote_includes :
194
+ if is_windows :
195
+ commands += [
196
+ "target_include_directories(%s %s %s)" % (info .name , info .modifier or "PUBLIC" , " " .join (info .quote_includes )),
197
+ ]
198
+ else :
199
+ commands += [
200
+ "target_compile_options(%s %s %s)" % (info .name , info .modifier or "PUBLIC" , " " .join (["-iquote%s" % i for i in info .quote_includes ])),
201
+ ]
183
202
if info .copts and info .modifier != "INTERFACE" :
184
203
commands += [
185
204
"target_compile_options(%s PRIVATE %s)" % (info .name , " " .join (info .copts )),
@@ -219,8 +238,10 @@ def _generate_cmake_impl(ctx):
219
238
inputs += info .inputs
220
239
infos [info .name ] = info
221
240
241
+ is_windows = ctx .target_platform_has_constraint (ctx .attr ._windows [platform_common .ConstraintValueInfo ])
242
+
222
243
for info in infos .values ():
223
- commands += _map_cmake_info (info )
244
+ commands += _map_cmake_info (info , is_windows )
224
245
commands .append ("" )
225
246
226
247
for include in ctx .attr .includes :
@@ -246,5 +267,6 @@ generate_cmake = rule(
246
267
attrs = {
247
268
"targets" : attr .label_list (aspects = [cmake_aspect ]),
248
269
"includes" : attr .label_list (providers = [GeneratedCmakeFiles ]),
270
+ "_windows" : attr .label (default = "@platforms//os:windows" ),
249
271
},
250
272
)
0 commit comments