77# above-listed licenses.
88
99load("@prelude//cxx:cxx_toolchain_types.bzl", "CxxToolchainInfo")
10+ load("@prelude//:paths.bzl", "paths")
1011load("flags_parser_utils.bxl", "flatten_flag_lists", "get_compiler_settings_from_flags")
1112load("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
2387def _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
71125def _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)
0 commit comments