@@ -7,7 +7,9 @@ CmakeInfo = provider(
77 "hdrs" : "" ,
88 "srcs" : "" ,
99 "deps" : "" ,
10+ "system_includes" : "" ,
1011 "includes" : "" ,
12+ "quote_includes" : "" ,
1113 "stripped_includes" : "" ,
1214 "imported_static_libs" : "" ,
1315 "imported_dynamic_libs" : "" ,
@@ -45,6 +47,10 @@ def _file_kind(file):
4547 return "dynamic_lib"
4648 return None
4749
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+
4854def _cmake_aspect_impl (target , ctx ):
4955 if not ctx .rule .kind .startswith ("cc_" ):
5056 return [CmakeInfo (name = None , transitive_deps = depset ())]
@@ -82,18 +88,17 @@ def _cmake_aspect_impl(target, ctx):
8288 linkopts += [ctx .expand_make_variables ("linkopts" , o , {}) for o in ctx .rule .attr .linkopts ]
8389
8490 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 )
8997
9098 # strip prefix is special, as in bazel it creates a _virtual_includes directory with symlinks
9199 # as we want to avoid relying on bazel having done that, we must undo that mechanism
92100 # also for some reason cmake fails to propagate these with target_include_directories,
93101 # 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 == "." ))]
97102 stripped_includes = []
98103 if getattr (ctx .rule .attr , "strip_include_prefix" , "" ):
99104 prefix = ctx .rule .attr .strip_include_prefix .strip ("/" )
@@ -108,7 +113,6 @@ def _cmake_aspect_impl(target, ctx):
108113 "${BAZEL_EXEC_ROOT}/%s/%s" % (ctx .var ["BINDIR" ], prefix ), # generated
109114 ]
110115
111- copts = [opt for opt in copts if not opt .startswith ("-I" )]
112116 deps = [dep [CmakeInfo ] for dep in deps if CmakeInfo in dep ]
113117
114118 # 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):
127131 srcs = srcs ,
128132 deps = [dep for dep in deps if dep .name != None ],
129133 includes = includes ,
134+ system_includes = system_includes ,
135+ quote_includes = quote_includes ,
130136 stripped_includes = stripped_includes ,
131137 imported_static_libs = static_libs ,
132138 imported_dynamic_libs = dynamic_libs ,
@@ -145,7 +151,7 @@ cmake_aspect = aspect(
145151 fragments = ["cpp" ],
146152)
147153
148- def _map_cmake_info (info ):
154+ def _map_cmake_info (info , is_windows ):
149155 args = " " .join ([info .name , info .modifier ] + info .hdrs + info .srcs ).strip ()
150156 commands = [
151157 "add_%s(%s)" % (info .kind , args ),
@@ -180,6 +186,19 @@ def _map_cmake_info(info):
180186 commands += [
181187 "target_include_directories(%s %s %s)" % (info .name , info .modifier or "PUBLIC" , " " .join (info .includes )),
182188 ]
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+ ]
183202 if info .copts and info .modifier != "INTERFACE" :
184203 commands += [
185204 "target_compile_options(%s PRIVATE %s)" % (info .name , " " .join (info .copts )),
@@ -219,8 +238,10 @@ def _generate_cmake_impl(ctx):
219238 inputs += info .inputs
220239 infos [info .name ] = info
221240
241+ is_windows = ctx .target_platform_has_constraint (ctx .attr ._windows [platform_common .ConstraintValueInfo ])
242+
222243 for info in infos .values ():
223- commands += _map_cmake_info (info )
244+ commands += _map_cmake_info (info , is_windows )
224245 commands .append ("" )
225246
226247 for include in ctx .attr .includes :
@@ -246,5 +267,6 @@ generate_cmake = rule(
246267 attrs = {
247268 "targets" : attr .label_list (aspects = [cmake_aspect ]),
248269 "includes" : attr .label_list (providers = [GeneratedCmakeFiles ]),
270+ "_windows" : attr .label (default = "@platforms//os:windows" ),
249271 },
250272)
0 commit comments