Skip to content

Commit 55cc722

Browse files
committed
Use headers as raw headers when generating vsgo projects.
1 parent 922de49 commit 55cc722

File tree

3 files changed

+114
-47
lines changed

3 files changed

+114
-47
lines changed

prelude/ide_integrations/visual_studio/get_attrs.bxl

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,19 @@ def get_unified_value(attrs, common_key: str, platform_key: str, toolchain = "wi
7070
all_flags.extend(flags)
7171
return all_flags
7272

73+
def _get_header_map_dict(attrs, key: str, toolchain:str|None) -> dict:
74+
headers = attrs.get(key)
75+
if not headers:
76+
return {}
77+
78+
if not isinstance(headers, dict):
79+
headers = {h.short_path(): h for h in headers}
80+
if not toolchain:
81+
return headers
82+
83+
result = {k: v for k, v in headers.items() if _platform_regex_match(v[0], toolchain)}
84+
return result
85+
7386
def get_cxx_toolchain(target: bxl.ConfiguredTargetNode, bxl_ctx) -> Dependency | None:
7487
attrs = target.resolved_attrs_lazy(bxl_ctx)
7588
return attrs.get("_cxx_toolchain")
@@ -94,10 +107,10 @@ def _get_headers(attrs) -> list:
94107

95108
def _get_exported_headers(attrs) -> dict:
96109
# TODO: support get dict without taking keys or values in get_unified_value.
97-
return dict(zip(
98-
get_unified_value(attrs, "exported_headers", "exported_platform_headers", take_values = False),
99-
get_unified_value(attrs, "exported_headers", "exported_platform_headers", take_values = True),
100-
))
110+
headers = _get_header_map_dict(attrs, "exported_headers", None)
111+
platform_headers = _get_header_map_dict(attrs, "exported_platform_headers", "windows")
112+
113+
return headers | platform_headers
101114

102115
def _get_raw_headers(attrs) -> list:
103116
return attrs.get("raw_headers") or []

prelude/ide_integrations/visual_studio/get_compiler_settings.bxl

Lines changed: 96 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -7,66 +7,120 @@
77
# above-listed licenses.
88

99
load("@prelude//cxx:cxx_toolchain_types.bzl", "CxxToolchainInfo")
10+
load("@prelude//:paths.bzl", "paths")
1011
load("flags_parser_utils.bxl", "flatten_flag_lists", "get_compiler_settings_from_flags")
1112
load("get_attrs.bxl", "get_attrs")
12-
load("utils.bxl", "basename", "dedupe_by_value", "dirname", "escape_xml", "get_argsfiles_output_path", "get_project_file_path", "h", "normcase", "normpath")
13+
load("utils.bxl", "dedupe_by_value", "dirname", "escape_xml", "get_argsfiles_output_path", "get_project_file_path", "h", "normcase", "normcase_backwards")
1314

14-
def _get_additional_include_directories(target: bxl.ConfiguredTargetNode, attrs: dict) -> list:
15-
dirs = attrs["include_directories"]
16-
dirs = [target.label.package + "/" + d for d in dirs]
15+
def _get_package_folder_relative_to_root(target: bxl.ConfiguredTargetNode, bxl_ctx) -> str:
16+
cell = target.label.cell
17+
package = target.label.package
18+
cell_map = bxl_ctx.audit().cell([cell, "root"])
1719

20+
root_path = cell_map["root"].replace("\\", "/")
21+
cell_path = cell_map[cell].replace("\\", "/")
22+
23+
result = paths.relativize(cell_path, root_path)
24+
if package:
25+
if result:
26+
result += "/"
27+
result += package
28+
29+
return result
30+
31+
def _get_include_directories_from_attributes(target: bxl.ConfiguredTargetNode, attrs: dict, fields: list[str], bxl_ctx) -> list:
32+
package_folder_relative_to_root = _get_package_folder_relative_to_root(target, bxl_ctx)
33+
34+
dirs = []
35+
for f in fields:
36+
dirs += attrs[f]
37+
38+
dirs = [normcase("$(RepoRoot)\\" + package_folder_relative_to_root + "/" + d) for d in dirs]
39+
return dirs
40+
41+
def _get_additional_include_directories(target: bxl.ConfiguredTargetNode, attrs: dict, bxl_ctx) -> list:
1842
# Headers shall not be directly added to additional include directories.
1943

20-
dirs = ["$(RepoRoot)\\" + d for d in dirs]
21-
return dedupe_by_value(dirs)
44+
dirs = _get_include_directories_from_attributes(target, attrs, ["include_directories"], bxl_ctx)
45+
dirs = dedupe_by_value(dirs)
46+
47+
return dirs
48+
49+
50+
def _as_raw_header(
51+
label,
52+
# The full name used to include the header.
53+
name: str,
54+
header: Artifact):
55+
"""
56+
Return path to pass to `include_directories` to treat the given header as
57+
a raw header.
58+
"""
59+
name = paths.normalize(name)
60+
61+
62+
if not header.is_source:
63+
return None
64+
65+
# To include the header via its name using raw headers and include dirs,
66+
# it needs to be a suffix of its original path, and we'll strip the include
67+
# name to get the include dir used to include it.
68+
path = paths.join(label.package, header.short_path)
69+
path = paths.normalize(path)
70+
base = paths.strip_suffix(path, name)
71+
if base == None:
72+
return None
73+
74+
# If the include dir is underneath our package, then just relativize to find
75+
# out package-relative path.
76+
if len(base) >= len(label.package):
77+
return paths.relativize(base, label.package)
78+
79+
# Otherwise, this include dir needs to reference a parent dir.
80+
num_parents = (
81+
len(label.package.split("/")) -
82+
(0 if not base else len(base.split("/")))
83+
)
84+
return "/".join([".."] * num_parents)
85+
2286

2387
def _get_exported_additional_include_directories(target: bxl.ConfiguredTargetNode, attrs: dict, bxl_ctx) -> list:
24-
dirs = attrs["public_include_directories"] + attrs["public_system_include_directories"]
25-
dirs = [target.label.package + "/" + d for d in dirs]
88+
label = target.label
2689

2790
# header_dirs is used in prebuilt_cxx_library (legacy Buck rule, still widely used for third-party code)
2891
# e.g., //third-party/gsl:gsl
29-
dirs += attrs["header_dirs"]
92+
attr_fields = [
93+
"public_include_directories",
94+
"public_system_include_directories",
95+
]
96+
97+
dirs_by_attribute = _get_include_directories_from_attributes(target, attrs, attr_fields, bxl_ctx)
98+
dirs_by_attribute += [normcase_backwards(d) for d in attrs["header_dirs"]]
3099

31-
# TODO: handle header files with header_path_prefix
100+
dirs = []
101+
102+
package_root = _get_package_folder_relative_to_root(target, bxl_ctx)
32103
for name, path in attrs["exported_headers"].items():
33-
header_namespace = attrs["header_namespace"]
34-
if header_namespace != None:
35-
if name == path:
36-
# Assuming exported_header is a list and no customized export name specified.
37-
# e.g.,
38-
# header: arvr/projects/xrtech/resources/FaceTracker/models:FaceWaveBinaryResources https://fburl.com/code/ee9ewpv7
39-
# usage: arvr/projects/facetracking/FaceWave:OVRLipSyncCommon https://fburl.com/code/76zx2fmw
40-
name = header_namespace + "/" + basename(name)
41-
else:
42-
# e.g.,
43-
# header: xplat/ocean/impl/ocean/base:base https://fburl.com/code/uiyr5ay9
44-
# usage: xplat/ocean/impl/ocean/math:math https://fburl.com/code/ebtcvn44
45-
name = header_namespace + "/" + name
46-
name = normcase(name)
47-
48-
# If file path is in generated buck-out, the file will be either not available or more correct form buck-headers exists.
49-
if "buck-out" not in path and path.endswith(name):
50-
# e.g.,
51-
# header: xplat/ocean/impl/ocean/base:base https://fburl.com/code/uiyr5ay9
52-
# usage: xplat/ocean/impl/ocean/math:math https://fburl.com/code/ebtcvn44
53-
include_dir = path.removesuffix(name)
54-
if include_dir:
55-
dirs.append(include_dir)
104+
if not "buck-out" in path:
105+
source_artifact = bxl_ctx.fs.source(path.replace("\\", "/"))
106+
as_raw = _as_raw_header(label, name, source_artifact)
107+
if as_raw != None:
108+
include_dir = package_root
109+
if as_raw:
110+
include_dir += "/" + as_raw
111+
dirs.append(normcase_backwards(include_dir))
56112
else:
57113
# Header tree created by buck. This is the most correct form but depends on previous local build to materialize.
58114
# e.g.,
59115
# header: xplat/third-party/yajl:yajl https://fburl.com/code/xqzlvuot
60116
# usage: xplat/mobileconfig/FBMobileConfigCore:FBMobileConfigCore https://fburl.com/code/p4qw1cx3
61117
argsfiles_output_path = get_argsfiles_output_path(target, bxl_ctx)
62118
if argsfiles_output_path:
63-
dirs.append(dirname(argsfiles_output_path) + "/buck-headers")
119+
include_dir = dirname(argsfiles_output_path) + "/buck-headers"
120+
dirs.append(normcase_backwards(include_dir))
64121

65-
dirs = [normpath(d) for d in dirs]
66-
dirs = dedupe_by_value(dirs)
67-
dirs = ["$(RepoRoot)\\" + d for d in dirs]
68-
69-
return dirs
122+
dirs = [normcase("$(RepoRoot)\\" + d) for d in dirs]
123+
return dedupe_by_value(dirs + dirs_by_attribute)
70124

71125
def _format_compiler_settings(compiler_settings: dict) -> dict:
72126
# Starlark passed in reference of dict. We don't want to accidentally override values, thus creating hard copy.
@@ -80,11 +134,11 @@ def _format_compiler_settings(compiler_settings: dict) -> dict:
80134
concat_compiler_settings["ForcedIncludeFiles"] = ";".join(compiler_settings["ForcedIncludeFiles"] + ["%(ForcedIncludeFiles)"])
81135
return concat_compiler_settings
82136

83-
def get_compiler_settings(target: bxl.ConfiguredTargetNode, attrs: dict) -> dict:
137+
def get_compiler_settings(target: bxl.ConfiguredTargetNode, attrs: dict, bxl_ctx) -> dict:
84138
"""return private compiler settings to be written to .vcxproj for given buck target"""
85139
compiler_flags = flatten_flag_lists(attrs["preprocessor_flags"] + attrs["compiler_flags"])
86140
compiler_settings = get_compiler_settings_from_flags(compiler_flags)
87-
compiler_settings["AdditionalIncludeDirectories"].extend(_get_additional_include_directories(target, attrs))
141+
compiler_settings["AdditionalIncludeDirectories"].extend(_get_additional_include_directories(target, attrs, bxl_ctx))
88142

89143
return compiler_settings
90144

@@ -130,7 +184,7 @@ def materialize_compiler_settings_file(target_node, actions, cxx_toolchain_info,
130184
else:
131185
exported_compiler_settings = get_exported_compiler_settings(target, attrs_input, ctx)
132186

133-
settings["compiler_settings"] = get_compiler_settings(target_node, attrs_input)
187+
settings["compiler_settings"] = get_compiler_settings(target_node, attrs_input, ctx)
134188
settings["exported_compiler_settings"] = exported_compiler_settings
135189

136190
ctx.bxl_actions().actions.write_json(outputs[out].as_output(), settings, pretty = True)

prelude/ide_integrations/visual_studio/get_vs_settings.bxl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,7 @@ def get_vs_settings(target: bxl.ConfiguredTargetNode, toolchain, attrs: dict, vs
233233

234234
vs_settings["CompilerSettings"] = merge(
235235
aggregated_private_compiler_settings,
236-
get_compiler_settings(target, attrs),
236+
get_compiler_settings(target, attrs, bxl_ctx),
237237
)
238238
vs_settings["LinkerSettings"] = merge(
239239
aggregated_private_linker_settings,

0 commit comments

Comments
 (0)