Vendor dependencies
Let's see how I like this workflow.
This commit is contained in:
parent
34d1830413
commit
9c435dc440
7500 changed files with 1665121 additions and 99 deletions
13
vendor/cxx/tools/buck/buildscript.bzl
vendored
Normal file
13
vendor/cxx/tools/buck/buildscript.bzl
vendored
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
def buildscript_args(
|
||||
name,
|
||||
package_name,
|
||||
buildscript_rule,
|
||||
cfgs,
|
||||
features,
|
||||
outfile,
|
||||
version):
|
||||
native.genrule(
|
||||
name = name,
|
||||
out = outfile,
|
||||
cmd = "env RUSTC=rustc TARGET= $(exe %s) | sed -n s/^cargo:rustc-cfg=/--cfg=/p > ${OUT}" % buildscript_rule,
|
||||
)
|
||||
3
vendor/cxx/tools/buck/prelude/CHANGELOG.md
vendored
Normal file
3
vendor/cxx/tools/buck/prelude/CHANGELOG.md
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
# Buck2 Prelude
|
||||
|
||||
* Initial version.
|
||||
45
vendor/cxx/tools/buck/prelude/CODE_OF_CONDUCT.md
vendored
Normal file
45
vendor/cxx/tools/buck/prelude/CODE_OF_CONDUCT.md
vendored
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
# Open Source Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to make participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to creating a positive environment include:
|
||||
|
||||
Using welcoming and inclusive language
|
||||
Being respectful of differing viewpoints and experiences
|
||||
Gracefully accepting constructive criticism
|
||||
Focusing on what is best for the community
|
||||
Showing empathy towards other community members
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
The use of sexualized language or imagery and unwelcome sexual attention or advances
|
||||
Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
Public or private harassment
|
||||
Publishing others’ private information, such as a physical or electronic address, without explicit permission
|
||||
Other conduct which could reasonably be considered inappropriate in a professional setting
|
||||
|
||||
## Our Responsibilities
|
||||
|
||||
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies within all project spaces, and it also applies when an individual is representing the project or its community in public spaces. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at opensource-conduct@fb.com. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
|
||||
|
||||
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project’s leadership.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
||||
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
|
||||
|
||||
[homepage]: https://www.contributor-covenant.org
|
||||
49
vendor/cxx/tools/buck/prelude/CONTRIBUTING.md
vendored
Normal file
49
vendor/cxx/tools/buck/prelude/CONTRIBUTING.md
vendored
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
# Contributing to Buck2 Prelude
|
||||
|
||||
This repository is a subset of <https://github.com/facebookincubator/buck2>.
|
||||
You can contribute to either that repo, or this repo - changes will be mirrored to both.
|
||||
|
||||
We want to make contributing to this project as easy and transparent as possible.
|
||||
|
||||
## Our Development Process
|
||||
|
||||
Buck2 Prelude is currently developed in Facebook's internal repositories and then exported
|
||||
out to GitHub by a Facebook team member; however, we invite you to submit pull
|
||||
requests as described below.
|
||||
|
||||
## Pull Requests
|
||||
|
||||
We actively welcome your pull requests.
|
||||
|
||||
1. Fork the repo and create your branch from `main`.
|
||||
2. If you've added code that should be tested, add tests.
|
||||
3. If you've changed APIs, update the documentation.
|
||||
4. Ensure the test suite passes.
|
||||
5. Make sure your code lints.
|
||||
6. If you haven't already, complete the Contributor License Agreement ("CLA").
|
||||
|
||||
## Contributor License Agreement ("CLA")
|
||||
|
||||
In order to accept your pull request, we need you to submit a CLA. You only need
|
||||
to do this once to work on any of Facebook's open source projects.
|
||||
|
||||
Complete your CLA here: <https://code.facebook.com/cla>
|
||||
|
||||
## Issues
|
||||
|
||||
We use GitHub issues to track public bugs. Please ensure your description is
|
||||
clear and has sufficient instructions to be able to reproduce the issue.
|
||||
|
||||
Facebook has a [bounty program](https://www.facebook.com/whitehat/) for the safe
|
||||
disclosure of security bugs. In those cases, please go through the process
|
||||
outlined on that page and do not file a public issue.
|
||||
|
||||
## Coding Style
|
||||
|
||||
We use several Python formatters.
|
||||
|
||||
## License
|
||||
|
||||
By contributing to Buck2 Prelude, you agree that your contributions will be
|
||||
licensed under both the [LICENSE-MIT](LICENSE-MIT) and [LICENSE-APACHE](LICENSE-APACHE)
|
||||
files in the root directory of this source tree.
|
||||
201
vendor/cxx/tools/buck/prelude/LICENSE-APACHE
vendored
Normal file
201
vendor/cxx/tools/buck/prelude/LICENSE-APACHE
vendored
Normal file
|
|
@ -0,0 +1,201 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
21
vendor/cxx/tools/buck/prelude/LICENSE-MIT
vendored
Normal file
21
vendor/cxx/tools/buck/prelude/LICENSE-MIT
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
9
vendor/cxx/tools/buck/prelude/README.md
vendored
Normal file
9
vendor/cxx/tools/buck/prelude/README.md
vendored
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
# Buck2 Prelude
|
||||
|
||||
This repo contains a copy of the Buck2 Prelude, which is often included as a submodule with a Buck2 project.
|
||||
To obtain a copy of this repo, and set up other details of a Buck2, you should usually run `buck2 init`.
|
||||
Most information can be found on the main [Buck2 GitHub project](https://github.com/facebookincubator/buck2).
|
||||
|
||||
## License
|
||||
|
||||
Buck2 Prelude is both MIT and Apache License, Version 2.0 licensed, as found in the [LICENSE-MIT](LICENSE-MIT) and [LICENSE-APACHE](LICENSE-APACHE) files.
|
||||
11
vendor/cxx/tools/buck/prelude/TARGETS
vendored
Normal file
11
vendor/cxx/tools/buck/prelude/TARGETS
vendored
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
load("@fbcode_macros//build_defs:native_rules.bzl", "buck_filegroup")
|
||||
load("@fbsource//tools/build_defs:glob_defs.bzl", "glob")
|
||||
|
||||
buck_filegroup(
|
||||
name = "prelude",
|
||||
srcs = glob(
|
||||
["**"],
|
||||
# Context: https://fb.workplace.com/groups/buck2users/posts/3121903854732641/
|
||||
exclude = ["**/.pyre_configuration.local"],
|
||||
),
|
||||
)
|
||||
22
vendor/cxx/tools/buck/prelude/alias.bzl
vendored
Normal file
22
vendor/cxx/tools/buck/prelude/alias.bzl
vendored
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
# Implementation of aliases build rules.
|
||||
|
||||
def alias_impl(ctx: "context") -> ["provider"]:
|
||||
return ctx.attrs.actual.providers
|
||||
|
||||
def configured_alias_impl(ctx: "context") -> ["provider"]:
|
||||
if ctx.attrs.configured_actual != None:
|
||||
return ctx.attrs.configured_actual.providers
|
||||
if ctx.attrs.fallback_actual != None:
|
||||
return ctx.attrs.fallback_actual.providers
|
||||
fail("must set one of `configured_actual` or `fallback_actual`")
|
||||
|
||||
def versioned_alias_impl(_ctx: "context") -> ["provider"]:
|
||||
# Should be intercepted in macro stub and converted to `alias`.
|
||||
fail("unsupported")
|
||||
109
vendor/cxx/tools/buck/prelude/android/aapt2_link.bzl
vendored
Normal file
109
vendor/cxx/tools/buck/prelude/android/aapt2_link.bzl
vendored
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load("@prelude//android:android_providers.bzl", "Aapt2LinkInfo")
|
||||
|
||||
BASE_PACKAGE_ID = 0x7f
|
||||
|
||||
def get_aapt2_link(
|
||||
ctx: "context",
|
||||
android_toolchain: "AndroidToolchainInfo",
|
||||
aapt2_compile_rules: ["artifact"],
|
||||
android_manifest: "artifact",
|
||||
includes_vector_drawables: bool.type = False,
|
||||
no_auto_version: bool.type = False,
|
||||
no_version_transitions: bool.type = False,
|
||||
no_auto_add_overlay: bool.type = False,
|
||||
use_proto_format: bool.type = False,
|
||||
no_resource_removal: bool.type = False,
|
||||
should_keep_raw_values: bool.type = False,
|
||||
package_id_offset: int.type = 0,
|
||||
resource_stable_ids: ["artifact", None] = None,
|
||||
preferred_density: [str.type, None] = None,
|
||||
min_sdk: [int.type, None] = None,
|
||||
filter_locales: bool.type = False,
|
||||
locales: [str.type] = [],
|
||||
compiled_resource_apks: ["artifact"] = [],
|
||||
additional_aapt2_params: [str.type] = [],
|
||||
extra_filtered_resources: [str.type] = []) -> Aapt2LinkInfo.type:
|
||||
aapt2_command = cmd_args(android_toolchain.aapt2)
|
||||
aapt2_command.add("link")
|
||||
|
||||
# aapt2 only supports @ for -R or input files, not for all args, so we pass in all "normal"
|
||||
# args here.
|
||||
resources_apk = ctx.actions.declare_output("resource-apk.ap_")
|
||||
aapt2_command.add(["-o", resources_apk.as_output()])
|
||||
proguard_config = ctx.actions.declare_output("proguard_config.pro")
|
||||
aapt2_command.add(["--proguard", proguard_config.as_output()])
|
||||
|
||||
# We don't need the R.java output, but aapt2 won't output R.txt unless we also request R.java.
|
||||
r_dot_java = ctx.actions.declare_output("initial-rdotjava")
|
||||
aapt2_command.add(["--java", r_dot_java.as_output()])
|
||||
r_dot_txt = ctx.actions.declare_output("R.txt")
|
||||
aapt2_command.add(["--output-text-symbols", r_dot_txt.as_output()])
|
||||
|
||||
aapt2_command.add(["--manifest", android_manifest])
|
||||
aapt2_command.add(["-I", android_toolchain.android_jar])
|
||||
|
||||
if includes_vector_drawables:
|
||||
aapt2_command.add("--no-version-vectors")
|
||||
if no_auto_version:
|
||||
aapt2_command.add("--no-auto-version")
|
||||
if no_version_transitions:
|
||||
aapt2_command.add("--no-version-transitions")
|
||||
if not no_auto_add_overlay:
|
||||
aapt2_command.add("--auto-add-overlay")
|
||||
if use_proto_format:
|
||||
aapt2_command.add("--proto-format")
|
||||
if no_resource_removal:
|
||||
aapt2_command.add("--no-resource-removal")
|
||||
if should_keep_raw_values:
|
||||
aapt2_command.add("--keep-raw-values")
|
||||
if package_id_offset != 0:
|
||||
aapt2_command.add(["--package-id", "0x{}".format(BASE_PACKAGE_ID + package_id_offset)])
|
||||
if resource_stable_ids != None:
|
||||
aapt2_command.add(["--stable-ids", resource_stable_ids])
|
||||
if preferred_density != None:
|
||||
aapt2_command.add(["--preferred-density", preferred_density])
|
||||
if min_sdk != None:
|
||||
aapt2_command.add(["--min-sdk-version", min_sdk])
|
||||
if filter_locales and len(locales) > 0:
|
||||
aapt2_command.add("-c")
|
||||
|
||||
# "NONE" means "en", update the list of locales
|
||||
aapt2_command.add(cmd_args([locale if locale != "NONE" else "en" for locale in locales], delimiter = ","))
|
||||
|
||||
for compiled_resource_apk in compiled_resource_apks:
|
||||
aapt2_command.add(["-I", compiled_resource_apk])
|
||||
|
||||
aapt2_compile_rules_args_file = ctx.actions.write("aapt2_compile_rules_args_file", cmd_args(aapt2_compile_rules, delimiter = " "))
|
||||
aapt2_command.add("-R")
|
||||
aapt2_command.add(cmd_args(aapt2_compile_rules_args_file, format = "@{}"))
|
||||
aapt2_command.hidden(aapt2_compile_rules)
|
||||
|
||||
aapt2_command.add(additional_aapt2_params)
|
||||
|
||||
ctx.actions.run(aapt2_command, category = "aapt2_link")
|
||||
|
||||
# The normal resource filtering apparatus is super slow, because it extracts the whole apk,
|
||||
# strips files out of it, then repackages it.
|
||||
#
|
||||
# This is a faster filtering step that just uses zip -d to remove entries from the archive.
|
||||
# It's also superbly dangerous.
|
||||
if len(extra_filtered_resources) > 0:
|
||||
filter_resources_cmd = cmd_args()
|
||||
filter_resources_cmd.add(["zip", "-d"])
|
||||
filter_resources_cmd.add(resources_apk)
|
||||
filter_resources_cmd.add(extra_filtered_resources)
|
||||
|
||||
ctx.actions.run(filter_resources_cmd, category = "aapt2_filter_resources")
|
||||
|
||||
return Aapt2LinkInfo(
|
||||
primary_resources_apk = resources_apk,
|
||||
proguard_config_file = proguard_config,
|
||||
r_dot_txt = r_dot_txt,
|
||||
)
|
||||
208
vendor/cxx/tools/buck/prelude/android/android.bzl
vendored
Normal file
208
vendor/cxx/tools/buck/prelude/android/android.bzl
vendored
Normal file
|
|
@ -0,0 +1,208 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load("@prelude//:attributes.bzl", "AaptMode", "DuplicateResourceBehaviour", "TargetCpuType")
|
||||
load("@prelude//java:dex_toolchain.bzl", "DexToolchainInfo")
|
||||
load("@prelude//java:java.bzl", "dex_min_sdk_version", "select_java_test_toolchain")
|
||||
load("@prelude//java:java_toolchain.bzl", "JavaPlatformInfo", "JavaTestToolchainInfo", "JavaToolchainInfo")
|
||||
load("@prelude//kotlin:kotlin_toolchain.bzl", "KotlinToolchainInfo")
|
||||
load("@prelude//genrule.bzl", "genrule_attributes")
|
||||
load(":android_apk.bzl", "android_apk_impl")
|
||||
load(":android_build_config.bzl", "android_build_config_impl")
|
||||
load(":android_instrumentation_apk.bzl", "android_instrumentation_apk_impl")
|
||||
load(":android_instrumentation_test.bzl", "android_instrumentation_test_impl")
|
||||
load(":android_library.bzl", "android_library_impl")
|
||||
load(":android_manifest.bzl", "android_manifest_impl")
|
||||
load(":android_prebuilt_aar.bzl", "android_prebuilt_aar_impl")
|
||||
load(":android_resource.bzl", "android_resource_impl")
|
||||
load(":android_toolchain.bzl", "AndroidPlatformInfo", "AndroidToolchainInfo")
|
||||
load(":apk_genrule.bzl", "apk_genrule_impl")
|
||||
load(":configuration.bzl", "cpu_split_transition", "cpu_split_transition_instrumentation_test_apk", "cpu_transition", "do_not_build_only_native_code_transition", "is_building_android_binary_attr")
|
||||
load(":gen_aidl.bzl", "gen_aidl_impl")
|
||||
load(":prebuilt_native_library.bzl", "prebuilt_native_library_impl")
|
||||
load(":robolectric_test.bzl", "robolectric_test_impl")
|
||||
load(":voltron.bzl", "android_app_modularity_impl")
|
||||
|
||||
def android_toolchain():
|
||||
return attrs.toolchain_dep(
|
||||
# FIXME: prelude// should be standalone (not refer to fbcode//)
|
||||
default = "fbcode//buck2/platform/toolchain:android",
|
||||
providers = [
|
||||
AndroidPlatformInfo,
|
||||
AndroidToolchainInfo,
|
||||
],
|
||||
)
|
||||
|
||||
def _dex_toolchain():
|
||||
return attrs.toolchain_dep(
|
||||
# FIXME: prelude// should be standalone (not refer to fbcode//)
|
||||
default = "fbcode//buck2/platform/toolchain:dex_for_android",
|
||||
providers = [
|
||||
DexToolchainInfo,
|
||||
],
|
||||
)
|
||||
|
||||
def java_toolchain_for_android():
|
||||
return attrs.toolchain_dep(
|
||||
# FIXME: prelude// should be standalone (not refer to fbcode//)
|
||||
default = "fbcode//buck2/platform/toolchain:java_for_android",
|
||||
providers = [
|
||||
JavaPlatformInfo,
|
||||
JavaToolchainInfo,
|
||||
],
|
||||
)
|
||||
|
||||
def _kotlin_toolchain():
|
||||
return attrs.toolchain_dep(
|
||||
# FIXME: prelude// should be standalone (not refer to fbcode//)
|
||||
default = "fbcode//buck2/platform/toolchain:kotlin",
|
||||
providers = [
|
||||
KotlinToolchainInfo,
|
||||
],
|
||||
)
|
||||
|
||||
def is_build_only_native_code():
|
||||
return select(
|
||||
{
|
||||
"DEFAULT": False,
|
||||
"fbsource//xplat/buck2/platform/android:build_only_native_code": True,
|
||||
},
|
||||
)
|
||||
|
||||
implemented_rules = {
|
||||
"android_app_modularity": android_app_modularity_impl,
|
||||
"android_binary": android_apk_impl,
|
||||
"android_build_config": android_build_config_impl,
|
||||
"android_instrumentation_apk": android_instrumentation_apk_impl,
|
||||
"android_instrumentation_test": android_instrumentation_test_impl,
|
||||
"android_library": android_library_impl,
|
||||
"android_manifest": android_manifest_impl,
|
||||
"android_prebuilt_aar": android_prebuilt_aar_impl,
|
||||
"android_resource": android_resource_impl,
|
||||
"apk_genrule": apk_genrule_impl,
|
||||
"gen_aidl": gen_aidl_impl,
|
||||
"prebuilt_native_library": prebuilt_native_library_impl,
|
||||
"robolectric_test": robolectric_test_impl,
|
||||
}
|
||||
|
||||
# Can't load `read_bool` here because it will cause circular load.
|
||||
DISABLE_SPLIT_TRANSITIONS = read_config("buck2", "android_td_disable_transitions_hack") in ("True", "true")
|
||||
|
||||
def _transition_dep_wrapper(split_transition_dep, transition_dep):
|
||||
if DISABLE_SPLIT_TRANSITIONS:
|
||||
return transition_dep
|
||||
return split_transition_dep
|
||||
|
||||
extra_attributes = {
|
||||
"android_aar": {
|
||||
"resources_root": attrs.option(attrs.string(), default = None),
|
||||
},
|
||||
"android_app_modularity": {
|
||||
"_android_toolchain": android_toolchain(),
|
||||
},
|
||||
"android_binary": {
|
||||
"aapt_mode": attrs.enum(AaptMode, default = "aapt1"), # Match default in V1
|
||||
"application_module_configs": attrs.dict(key = attrs.string(), value = attrs.list(attrs.transition_dep(cfg = cpu_transition)), sorted = False, default = {}),
|
||||
"build_config_values_file": attrs.option(attrs.one_of(attrs.transition_dep(cfg = cpu_transition), attrs.source()), default = None),
|
||||
"deps": attrs.list(_transition_dep_wrapper(split_transition_dep = attrs.split_transition_dep(cfg = cpu_split_transition), transition_dep = attrs.transition_dep(cfg = cpu_transition)), default = []),
|
||||
"dex_tool": attrs.string(default = "d8"), # Match default in V1
|
||||
"duplicate_resource_behavior": attrs.enum(DuplicateResourceBehaviour, default = "allow_by_default"), # Match default in V1
|
||||
"manifest": attrs.option(attrs.one_of(attrs.transition_dep(cfg = cpu_transition), attrs.source()), default = None),
|
||||
"manifest_skeleton": attrs.option(attrs.one_of(attrs.transition_dep(cfg = cpu_transition), attrs.source()), default = None),
|
||||
"min_sdk_version": attrs.option(attrs.int(), default = None),
|
||||
"module_manifest_skeleton": attrs.option(attrs.one_of(attrs.transition_dep(cfg = cpu_transition), attrs.source()), default = None),
|
||||
"_android_installer": attrs.default_only(attrs.label(
|
||||
# FIXME: prelude// should be standalone (not refer to buck//)
|
||||
default = "buck//src/com/facebook/buck/installer/android:android_installer",
|
||||
)),
|
||||
"_android_toolchain": android_toolchain(),
|
||||
"_dex_toolchain": _dex_toolchain(),
|
||||
"_is_building_android_binary": attrs.default_only(attrs.bool(default = True)),
|
||||
"_java_toolchain": java_toolchain_for_android(),
|
||||
},
|
||||
"android_build_config": {
|
||||
"_android_toolchain": android_toolchain(),
|
||||
"_build_only_native_code": attrs.default_only(attrs.bool(default = is_build_only_native_code())),
|
||||
"_is_building_android_binary": is_building_android_binary_attr(),
|
||||
"_java_toolchain": java_toolchain_for_android(),
|
||||
},
|
||||
"android_instrumentation_apk": {
|
||||
"aapt_mode": attrs.enum(AaptMode, default = "aapt1"), # Match default in V1
|
||||
"apk": attrs.transition_dep(cfg = do_not_build_only_native_code_transition),
|
||||
"cpu_filters": attrs.list(attrs.enum(TargetCpuType), default = []),
|
||||
"deps": attrs.list(_transition_dep_wrapper(split_transition_dep = attrs.split_transition_dep(cfg = cpu_split_transition_instrumentation_test_apk), transition_dep = attrs.transition_dep(cfg = cpu_transition)), default = []),
|
||||
"dex_tool": attrs.string(default = "d8"), # Match default in V1
|
||||
"manifest": attrs.option(attrs.one_of(attrs.transition_dep(cfg = cpu_transition), attrs.source()), default = None),
|
||||
"manifest_skeleton": attrs.option(attrs.one_of(attrs.transition_dep(cfg = cpu_transition), attrs.source()), default = None),
|
||||
"min_sdk_version": attrs.option(attrs.int(), default = None),
|
||||
"_android_toolchain": android_toolchain(),
|
||||
"_dex_toolchain": _dex_toolchain(),
|
||||
"_is_building_android_binary": attrs.default_only(attrs.bool(default = True)),
|
||||
"_java_toolchain": java_toolchain_for_android(),
|
||||
},
|
||||
"android_instrumentation_test": {
|
||||
"_android_toolchain": android_toolchain(),
|
||||
"_java_toolchain": java_toolchain_for_android(),
|
||||
},
|
||||
"android_library": {
|
||||
"resources_root": attrs.option(attrs.string(), default = None),
|
||||
"_android_toolchain": android_toolchain(),
|
||||
"_build_only_native_code": attrs.default_only(attrs.bool(default = is_build_only_native_code())),
|
||||
"_dex_min_sdk_version": attrs.default_only(attrs.option(attrs.int(), default = dex_min_sdk_version())),
|
||||
"_dex_toolchain": _dex_toolchain(),
|
||||
"_is_building_android_binary": is_building_android_binary_attr(),
|
||||
"_java_toolchain": java_toolchain_for_android(),
|
||||
"_kotlin_toolchain": _kotlin_toolchain(),
|
||||
},
|
||||
"android_manifest": {
|
||||
"_android_toolchain": android_toolchain(),
|
||||
},
|
||||
"android_prebuilt_aar": {
|
||||
# Prebuilt jars are quick to build, and often contain third-party code, which in turn is
|
||||
# often a source of annotations and constants. To ease migration to ABI generation from
|
||||
# source without deps, we have them present during ABI gen by default.
|
||||
"required_for_source_only_abi": attrs.bool(default = True),
|
||||
"_android_toolchain": android_toolchain(),
|
||||
"_build_only_native_code": attrs.default_only(attrs.bool(default = is_build_only_native_code())),
|
||||
"_dex_min_sdk_version": attrs.default_only(attrs.option(attrs.int(), default = dex_min_sdk_version())),
|
||||
"_dex_toolchain": _dex_toolchain(),
|
||||
"_java_toolchain": java_toolchain_for_android(),
|
||||
},
|
||||
"android_resource": {
|
||||
"assets": attrs.option(attrs.one_of(attrs.source(allow_directory = True), attrs.dict(key = attrs.string(), value = attrs.source(), sorted = True)), default = None),
|
||||
"project_assets": attrs.option(attrs.source(allow_directory = True), default = None),
|
||||
"project_res": attrs.option(attrs.source(allow_directory = True), default = None),
|
||||
"res": attrs.option(attrs.one_of(attrs.source(allow_directory = True), attrs.dict(key = attrs.string(), value = attrs.source(), sorted = True)), default = None),
|
||||
"_android_toolchain": android_toolchain(),
|
||||
"_build_only_native_code": attrs.default_only(attrs.bool(default = is_build_only_native_code())),
|
||||
},
|
||||
"apk_genrule": genrule_attributes() | {
|
||||
"type": attrs.string(default = "apk"),
|
||||
},
|
||||
"gen_aidl": {
|
||||
"import_paths": attrs.list(attrs.arg(), default = []),
|
||||
"_android_toolchain": android_toolchain(),
|
||||
"_java_toolchain": java_toolchain_for_android(),
|
||||
},
|
||||
"prebuilt_native_library": {
|
||||
"native_libs": attrs.source(allow_directory = True),
|
||||
},
|
||||
"robolectric_test": {
|
||||
"resources_root": attrs.option(attrs.string(), default = None),
|
||||
"robolectric_runtime_dependencies": attrs.list(attrs.source(), default = []),
|
||||
"_android_toolchain": android_toolchain(),
|
||||
"_is_building_android_binary": attrs.default_only(attrs.bool(default = False)),
|
||||
"_java_test_toolchain": attrs.default_only(attrs.exec_dep(
|
||||
default = select_java_test_toolchain(),
|
||||
providers = [
|
||||
JavaTestToolchainInfo,
|
||||
],
|
||||
)),
|
||||
"_java_toolchain": java_toolchain_for_android(),
|
||||
"_kotlin_toolchain": _kotlin_toolchain(),
|
||||
},
|
||||
}
|
||||
334
vendor/cxx/tools/buck/prelude/android/android_apk.bzl
vendored
Normal file
334
vendor/cxx/tools/buck/prelude/android/android_apk.bzl
vendored
Normal file
|
|
@ -0,0 +1,334 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load("@prelude//android:android_binary_native_library_rules.bzl", "get_android_binary_native_library_info")
|
||||
load("@prelude//android:android_binary_resources_rules.bzl", "get_android_binary_resources_info")
|
||||
load("@prelude//android:android_build_config.bzl", "generate_android_build_config", "get_build_config_fields")
|
||||
load("@prelude//android:android_providers.bzl", "AndroidApkInfo", "AndroidApkUnderTestInfo", "BuildConfigField", "CPU_FILTER_TO_ABI_DIRECTORY", "ExopackageInfo", "merge_android_packageable_info")
|
||||
load("@prelude//android:android_toolchain.bzl", "AndroidToolchainInfo")
|
||||
load("@prelude//android:configuration.bzl", "get_deps_by_platform")
|
||||
load("@prelude//android:dex_rules.bzl", "get_multi_dex", "get_single_primary_dex", "get_split_dex_merge_config", "merge_to_single_dex", "merge_to_split_dex")
|
||||
load("@prelude//android:exopackage.bzl", "get_exopackage_flags")
|
||||
load("@prelude//android:preprocess_java_classes.bzl", "get_preprocessed_java_classes")
|
||||
load("@prelude//android:proguard.bzl", "get_proguard_output")
|
||||
load("@prelude//android:voltron.bzl", "get_target_to_module_mapping")
|
||||
load("@prelude//java:java_providers.bzl", "KeystoreInfo", "create_java_packaging_dep", "get_all_java_packaging_deps", "get_all_java_packaging_deps_from_packaging_infos")
|
||||
load("@prelude//utils:utils.bzl", "expect")
|
||||
|
||||
def android_apk_impl(ctx: "context") -> ["provider"]:
|
||||
sub_targets = {}
|
||||
|
||||
_verify_params(ctx)
|
||||
|
||||
cpu_filters = ctx.attrs.cpu_filters or CPU_FILTER_TO_ABI_DIRECTORY.keys()
|
||||
deps_by_platform = get_deps_by_platform(ctx)
|
||||
primary_platform = cpu_filters[0]
|
||||
deps = deps_by_platform[primary_platform]
|
||||
|
||||
no_dx_target_labels = [no_dx_target.label.raw_target() for no_dx_target in ctx.attrs.no_dx]
|
||||
java_packaging_deps = [packaging_dep for packaging_dep in get_all_java_packaging_deps(ctx, deps) if packaging_dep.dex and packaging_dep.dex.dex.owner.raw_target() not in no_dx_target_labels]
|
||||
|
||||
android_packageable_info = merge_android_packageable_info(ctx.label, ctx.actions, deps)
|
||||
build_config_infos = list(android_packageable_info.build_config_infos.traverse()) if android_packageable_info.build_config_infos else []
|
||||
|
||||
build_config_libs = _get_build_config_java_libraries(ctx, build_config_infos)
|
||||
java_packaging_deps += get_all_java_packaging_deps_from_packaging_infos(ctx, build_config_libs)
|
||||
|
||||
has_proguard_config = ctx.attrs.proguard_config != None or ctx.attrs.android_sdk_proguard_config == "default" or ctx.attrs.android_sdk_proguard_config == "optimized"
|
||||
should_pre_dex = not ctx.attrs.disable_pre_dex and not has_proguard_config and not ctx.attrs.preprocess_java_classes_bash
|
||||
|
||||
referenced_resources_lists = [java_packaging_dep.dex.referenced_resources for java_packaging_dep in java_packaging_deps] if ctx.attrs.trim_resource_ids and should_pre_dex else []
|
||||
resources_info = get_android_binary_resources_info(
|
||||
ctx,
|
||||
deps,
|
||||
android_packageable_info,
|
||||
java_packaging_deps,
|
||||
use_proto_format = False,
|
||||
referenced_resources_lists = referenced_resources_lists,
|
||||
manifest_entries = ctx.attrs.manifest_entries,
|
||||
)
|
||||
android_toolchain = ctx.attrs._android_toolchain[AndroidToolchainInfo]
|
||||
java_packaging_deps += [
|
||||
create_java_packaging_dep(
|
||||
ctx,
|
||||
r_dot_java.library_output.full_library,
|
||||
dex_weight_factor = android_toolchain.r_dot_java_weight_factor,
|
||||
)
|
||||
for r_dot_java in resources_info.r_dot_javas
|
||||
]
|
||||
|
||||
target_to_module_mapping_file = get_target_to_module_mapping(ctx, deps)
|
||||
if should_pre_dex:
|
||||
pre_dexed_libs = [java_packaging_dep.dex for java_packaging_dep in java_packaging_deps]
|
||||
if ctx.attrs.use_split_dex:
|
||||
dex_files_info = merge_to_split_dex(
|
||||
ctx,
|
||||
android_toolchain,
|
||||
pre_dexed_libs,
|
||||
get_split_dex_merge_config(ctx, android_toolchain),
|
||||
target_to_module_mapping_file,
|
||||
)
|
||||
else:
|
||||
dex_files_info = merge_to_single_dex(ctx, android_toolchain, pre_dexed_libs)
|
||||
else:
|
||||
jars_to_owners = {packaging_dep.jar: packaging_dep.jar.owner.raw_target() for packaging_dep in java_packaging_deps}
|
||||
if ctx.attrs.preprocess_java_classes_bash:
|
||||
jars_to_owners = get_preprocessed_java_classes(ctx, jars_to_owners)
|
||||
if has_proguard_config:
|
||||
proguard_output = get_proguard_output(ctx, jars_to_owners, java_packaging_deps, resources_info.proguard_config_file)
|
||||
jars_to_owners = proguard_output.jars_to_owners
|
||||
sub_targets["proguard_text_output"] = [
|
||||
DefaultInfo(
|
||||
default_outputs = [ctx.actions.symlinked_dir(
|
||||
"proguard_text_output",
|
||||
{artifact.basename: artifact for artifact in proguard_output.proguard_artifacts},
|
||||
)],
|
||||
),
|
||||
]
|
||||
else:
|
||||
proguard_output = None
|
||||
|
||||
if ctx.attrs.use_split_dex:
|
||||
dex_files_info = get_multi_dex(
|
||||
ctx,
|
||||
ctx.attrs._android_toolchain[AndroidToolchainInfo],
|
||||
jars_to_owners,
|
||||
ctx.attrs.primary_dex_patterns,
|
||||
proguard_output.proguard_configuration_output_file if proguard_output else None,
|
||||
proguard_output.proguard_mapping_output_file if proguard_output else None,
|
||||
is_optimized = has_proguard_config,
|
||||
apk_module_graph_file = target_to_module_mapping_file,
|
||||
)
|
||||
else:
|
||||
dex_files_info = get_single_primary_dex(
|
||||
ctx,
|
||||
ctx.attrs._android_toolchain[AndroidToolchainInfo],
|
||||
jars_to_owners.keys(),
|
||||
is_optimized = has_proguard_config,
|
||||
)
|
||||
|
||||
native_library_info = get_android_binary_native_library_info(ctx, android_packageable_info, deps_by_platform, apk_module_graph_file = target_to_module_mapping_file)
|
||||
unstripped_native_libs = native_library_info.unstripped_libs
|
||||
sub_targets["unstripped_native_libraries"] = [
|
||||
DefaultInfo(
|
||||
default_outputs = [ctx.actions.write("unstripped_native_libraries", unstripped_native_libs)],
|
||||
other_outputs = unstripped_native_libs,
|
||||
),
|
||||
]
|
||||
if resources_info.string_source_map:
|
||||
sub_targets["generate_string_resources"] = [DefaultInfo(default_outputs = [resources_info.string_source_map])]
|
||||
|
||||
if dex_files_info.primary_dex_class_names:
|
||||
sub_targets["primary_dex_class_names"] = [DefaultInfo(default_outputs = [dex_files_info.primary_dex_class_names])]
|
||||
|
||||
keystore = ctx.attrs.keystore[KeystoreInfo]
|
||||
output_apk = build_apk(
|
||||
label = ctx.label,
|
||||
actions = ctx.actions,
|
||||
android_toolchain = ctx.attrs._android_toolchain[AndroidToolchainInfo],
|
||||
keystore = keystore,
|
||||
dex_files_info = dex_files_info,
|
||||
native_library_info = native_library_info,
|
||||
resources_info = resources_info,
|
||||
compress_resources_dot_arsc = ctx.attrs.resource_compression == "enabled" or ctx.attrs.resource_compression == "enabled_with_strings_as_assets",
|
||||
)
|
||||
|
||||
exopackage_info = ExopackageInfo(
|
||||
secondary_dex_info = dex_files_info.secondary_dex_exopackage_info,
|
||||
native_library_info = native_library_info.exopackage_info,
|
||||
resources_info = resources_info.exopackage_info,
|
||||
)
|
||||
|
||||
return [
|
||||
AndroidApkInfo(apk = output_apk, manifest = resources_info.manifest),
|
||||
AndroidApkUnderTestInfo(
|
||||
java_packaging_deps = java_packaging_deps,
|
||||
keystore = keystore,
|
||||
manifest_entries = ctx.attrs.manifest_entries,
|
||||
prebuilt_native_library_dirs = native_library_info.apk_under_test_prebuilt_native_library_dirs,
|
||||
platforms = deps_by_platform.keys(),
|
||||
primary_platform = primary_platform,
|
||||
resource_infos = resources_info.unfiltered_resource_infos,
|
||||
shared_libraries = native_library_info.apk_under_test_shared_libraries,
|
||||
),
|
||||
DefaultInfo(default_outputs = [output_apk], other_outputs = _get_exopackage_outputs(exopackage_info), sub_targets = sub_targets),
|
||||
_get_install_info(ctx, output_apk = output_apk, manifest = resources_info.manifest, exopackage_info = exopackage_info),
|
||||
]
|
||||
|
||||
def build_apk(
|
||||
label: "label",
|
||||
actions: "actions",
|
||||
keystore: KeystoreInfo.type,
|
||||
android_toolchain: AndroidToolchainInfo.type,
|
||||
dex_files_info: "DexFilesInfo",
|
||||
native_library_info: "AndroidBinaryNativeLibsInfo",
|
||||
resources_info: "AndroidBinaryResourcesInfo",
|
||||
compress_resources_dot_arsc: bool.type = False) -> "artifact":
|
||||
output_apk = actions.declare_output("{}.apk".format(label.name))
|
||||
|
||||
apk_builder_args = cmd_args([
|
||||
android_toolchain.apk_builder[RunInfo],
|
||||
"--output-apk",
|
||||
output_apk.as_output(),
|
||||
"--resource-apk",
|
||||
resources_info.primary_resources_apk,
|
||||
"--dex-file",
|
||||
dex_files_info.primary_dex,
|
||||
"--keystore-path",
|
||||
keystore.store,
|
||||
"--keystore-properties-path",
|
||||
keystore.properties,
|
||||
"--zipalign_tool",
|
||||
android_toolchain.zipalign[RunInfo],
|
||||
])
|
||||
|
||||
if compress_resources_dot_arsc:
|
||||
apk_builder_args.add("--compress-resources-dot-arsc")
|
||||
|
||||
asset_directories = native_library_info.native_lib_assets + dex_files_info.secondary_dex_dirs
|
||||
asset_directories_file = actions.write("asset_directories.txt", asset_directories)
|
||||
apk_builder_args.hidden(asset_directories)
|
||||
native_library_directories = actions.write("native_library_directories", native_library_info.native_libs_for_primary_apk)
|
||||
apk_builder_args.hidden(native_library_info.native_libs_for_primary_apk)
|
||||
all_zip_files = [resources_info.packaged_string_assets] if resources_info.packaged_string_assets else []
|
||||
zip_files = actions.write("zip_files", all_zip_files)
|
||||
apk_builder_args.hidden(all_zip_files)
|
||||
jar_files_that_may_contain_resources = actions.write("jar_files_that_may_contain_resources", resources_info.jar_files_that_may_contain_resources)
|
||||
apk_builder_args.hidden(resources_info.jar_files_that_may_contain_resources)
|
||||
|
||||
apk_builder_args.add([
|
||||
"--asset-directories-list",
|
||||
asset_directories_file,
|
||||
"--native-libraries-directories-list",
|
||||
native_library_directories,
|
||||
"--zip-files-list",
|
||||
zip_files,
|
||||
"--jar-files-that-may-contain-resources-list",
|
||||
jar_files_that_may_contain_resources,
|
||||
])
|
||||
|
||||
actions.run(apk_builder_args, category = "apk_build")
|
||||
|
||||
return output_apk
|
||||
|
||||
def _get_install_info(ctx: "context", output_apk: "artifact", manifest: "artifact", exopackage_info: ExopackageInfo.type) -> InstallInfo.type:
|
||||
files = {
|
||||
ctx.attrs.name: output_apk,
|
||||
"manifest": manifest,
|
||||
"options": generate_install_config(ctx),
|
||||
}
|
||||
|
||||
secondary_dex_exopackage_info = exopackage_info.secondary_dex_info
|
||||
if secondary_dex_exopackage_info:
|
||||
files["secondary_dex_exopackage_info_directory"] = secondary_dex_exopackage_info.directory
|
||||
files["secondary_dex_exopackage_info_metadata"] = secondary_dex_exopackage_info.metadata
|
||||
|
||||
native_library_exopackage_info = exopackage_info.native_library_info
|
||||
if native_library_exopackage_info:
|
||||
files["native_library_exopackage_info_directory"] = native_library_exopackage_info.directory
|
||||
files["native_library_exopackage_info_metadata"] = native_library_exopackage_info.metadata
|
||||
|
||||
resources_info = exopackage_info.resources_info
|
||||
if resources_info:
|
||||
if resources_info.assets:
|
||||
files["resources_exopackage_assets"] = resources_info.assets
|
||||
files["resources_exopackage_assets_hash"] = resources_info.assets_hash
|
||||
|
||||
files["resources_exopackage_res"] = resources_info.res
|
||||
files["resources_exopackage_res_hash"] = resources_info.res_hash
|
||||
files["resources_exopackage_third_party_jar_resources"] = resources_info.third_party_jar_resources
|
||||
files["resources_exopackage_third_party_jar_resources_hash"] = resources_info.third_party_jar_resources_hash
|
||||
|
||||
if secondary_dex_exopackage_info or native_library_exopackage_info or resources_info:
|
||||
files["exopackage_agent_apk"] = ctx.attrs._android_toolchain[AndroidToolchainInfo].exopackage_agent_apk
|
||||
|
||||
return InstallInfo(
|
||||
installer = ctx.attrs._android_installer,
|
||||
files = files,
|
||||
)
|
||||
|
||||
def _get_build_config_java_libraries(ctx: "context", build_config_infos: ["AndroidBuildConfigInfo"]) -> ["JavaPackagingInfo"]:
|
||||
# BuildConfig deps should not be added for instrumented APKs because BuildConfig.class has
|
||||
# already been added to the APK under test.
|
||||
if ctx.attrs.package_type == "instrumented":
|
||||
return []
|
||||
|
||||
build_config_constants = [
|
||||
BuildConfigField(type = "boolean", name = "DEBUG", value = str(ctx.attrs.package_type != "release").lower()),
|
||||
BuildConfigField(type = "boolean", name = "IS_EXOPACKAGE", value = str(len(ctx.attrs.exopackage_modes) > 0).lower()),
|
||||
BuildConfigField(type = "int", name = "EXOPACKAGE_FLAGS", value = str(get_exopackage_flags(ctx.attrs.exopackage_modes))),
|
||||
]
|
||||
|
||||
default_build_config_fields = get_build_config_fields(ctx.attrs.build_config_values)
|
||||
|
||||
java_libraries = []
|
||||
java_packages_seen = []
|
||||
for build_config_info in build_config_infos:
|
||||
java_package = build_config_info.package
|
||||
expect(java_package not in java_packages_seen, "Got the same java_package {} for different AndroidBuildConfigs".format(java_package))
|
||||
java_packages_seen.append(java_package)
|
||||
|
||||
all_build_config_values = {}
|
||||
for build_config_field in build_config_info.build_config_fields + default_build_config_fields + build_config_constants:
|
||||
all_build_config_values[build_config_field.name] = build_config_field
|
||||
|
||||
java_libraries.append(generate_android_build_config(
|
||||
ctx,
|
||||
java_package,
|
||||
java_package,
|
||||
True, # use_constant_expressions
|
||||
all_build_config_values.values(),
|
||||
ctx.attrs.build_config_values_file[DefaultInfo].default_outputs[0] if type(ctx.attrs.build_config_values_file) == "dependency" else ctx.attrs.build_config_values_file,
|
||||
)[1])
|
||||
|
||||
return java_libraries
|
||||
|
||||
def _get_exopackage_outputs(exopackage_info: ExopackageInfo.type) -> ["artifact"]:
|
||||
outputs = []
|
||||
secondary_dex_exopackage_info = exopackage_info.secondary_dex_info
|
||||
if secondary_dex_exopackage_info:
|
||||
outputs.append(secondary_dex_exopackage_info.metadata)
|
||||
outputs.append(secondary_dex_exopackage_info.directory)
|
||||
|
||||
native_library_exopackage_info = exopackage_info.native_library_info
|
||||
if native_library_exopackage_info:
|
||||
outputs.append(native_library_exopackage_info.metadata)
|
||||
outputs.append(native_library_exopackage_info.directory)
|
||||
|
||||
resources_info = exopackage_info.resources_info
|
||||
if resources_info:
|
||||
outputs.append(resources_info.res)
|
||||
outputs.append(resources_info.res_hash)
|
||||
outputs.append(resources_info.third_party_jar_resources)
|
||||
outputs.append(resources_info.third_party_jar_resources_hash)
|
||||
|
||||
if resources_info.assets:
|
||||
outputs.append(resources_info.assets)
|
||||
outputs.append(resources_info.assets_hash)
|
||||
|
||||
return outputs
|
||||
|
||||
def _verify_params(ctx: "context"):
|
||||
expect(ctx.attrs.aapt_mode == "aapt2", "aapt1 is deprecated!")
|
||||
expect(ctx.attrs.dex_tool == "d8", "dx is deprecated!")
|
||||
expect(ctx.attrs.allow_r_dot_java_in_secondary_dex == True)
|
||||
|
||||
def generate_install_config(ctx: "context") -> "artifact":
|
||||
data = get_install_config()
|
||||
return ctx.actions.write_json("install_android_options.json", data)
|
||||
|
||||
def get_install_config() -> {str.type: ""}:
|
||||
# TODO: read from toolchains
|
||||
return {
|
||||
"adb_executable": read_config("android", "adb", "/opt/android_sdk/platform-tools/adb"),
|
||||
"adb_restart_on_failure": read_config("adb", "adb_restart_on_failure", "false"),
|
||||
"agent_port_base": read_config("adb", "agent_port_base", "2828"),
|
||||
"always_use_java_agent": read_config("adb", "always_use_java_agent", "false"),
|
||||
"is_zstd_compression_enabled": read_config("adb", "is_zstd_compression_enabled", "false"),
|
||||
"multi_install_mode": read_config("adb", "multi_install_mode", "false"),
|
||||
"skip_install_metadata": read_config("adb", "skip_install_metadata", "false"),
|
||||
}
|
||||
404
vendor/cxx/tools/buck/prelude/android/android_binary_native_library_rules.bzl
vendored
Normal file
404
vendor/cxx/tools/buck/prelude/android/android_binary_native_library_rules.bzl
vendored
Normal file
|
|
@ -0,0 +1,404 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load("@prelude//:paths.bzl", "paths")
|
||||
load("@prelude//android:android_providers.bzl", "AndroidBinaryNativeLibsInfo", "CPU_FILTER_TO_ABI_DIRECTORY", "ExopackageNativeInfo")
|
||||
load("@prelude//android:android_toolchain.bzl", "AndroidToolchainInfo")
|
||||
load("@prelude//android:voltron.bzl", "ROOT_MODULE", "all_targets_in_root_module", "get_apk_module_graph_info", "is_root_module")
|
||||
load("@prelude//linking:shared_libraries.bzl", "SharedLibraryInfo", "merge_shared_libraries", "traverse_shared_library_info")
|
||||
load("@prelude//utils:utils.bzl", "expect")
|
||||
|
||||
# Native libraries on Android are built for a particular Application Binary Interface (ABI). We
|
||||
# package native libraries for one (or more, for multi-arch builds) ABIs into an Android APK.
|
||||
#
|
||||
# Our native libraries come from two sources:
|
||||
# 1. "Prebuilt native library dirs", which are directory artifacts whose sub-directories are ABIs,
|
||||
# and those ABI subdirectories contain native libraries. These come from `android_prebuilt_aar`s
|
||||
# and `prebuilt_native_library`s, for example.
|
||||
# 2. "Native linkables". These are each a single shared library - `.so`s for one particular ABI.
|
||||
#
|
||||
# Native libraries can be packaged into Android APKs in two ways.
|
||||
# 1. As native libraries. This means that they are passed to the APK builder as native libraries,
|
||||
# and the APK builder will package `<ABI>/library.so` into the APK at `libs/<ABI>/library.so`.
|
||||
# 2. As assets. These are passed to the APK build as assets, and are stored at
|
||||
# `assets/lib/<ABI>/library.so` In the root module, we only package a native library as an
|
||||
# asset if it is eligible to be an asset (e.g. `can_be_asset` on a `cxx_library`), and
|
||||
# `package_asset_libraries` is set to True for the APK. We will additionally compress all the
|
||||
# assets into a single `assets/lib/libs.xz` (or `assets/libs/libs.zstd` for `zstd` compression)
|
||||
# if `compress_asset_libraries` is set to True for the APK. Regardless of whether we compress
|
||||
# the assets or not, we create a metadata file at `assets/libs/metadata.txt` that has a single
|
||||
# line entry for each packaged asset consisting of '<ABI/library_name> <file_size> <sha256>'.
|
||||
#
|
||||
# Any native library that is not part of the root module (i.e. it is part of some other Voltron
|
||||
# module) is automatically packaged as an asset, and the assets for each module are compressed
|
||||
# to a single `assets/<module_name>/libs.xz`. Similarly, the metadata for each module is stored
|
||||
# at `assets/<module_name>/libs.txt`.
|
||||
|
||||
def get_android_binary_native_library_info(
|
||||
ctx: "context",
|
||||
android_packageable_info: "AndroidPackageableInfo",
|
||||
deps_by_platform: {str.type: ["dependency"]},
|
||||
apk_module_graph_file: ["artifact", None] = None,
|
||||
prebuilt_native_library_dirs_to_exclude: ["PrebuiltNativeLibraryDir"] = [],
|
||||
shared_libraries_to_exclude: ["SharedLibrary"] = []) -> AndroidBinaryNativeLibsInfo.type:
|
||||
traversed_prebuilt_native_library_dirs = android_packageable_info.prebuilt_native_library_dirs.traverse() if android_packageable_info.prebuilt_native_library_dirs else []
|
||||
all_prebuilt_native_library_dirs = [native_lib for native_lib in traversed_prebuilt_native_library_dirs if native_lib not in prebuilt_native_library_dirs_to_exclude]
|
||||
|
||||
unstripped_libs = []
|
||||
all_shared_libraries = []
|
||||
platform_to_native_linkables = {}
|
||||
for platform, deps in deps_by_platform.items():
|
||||
shared_library_info = merge_shared_libraries(
|
||||
ctx.actions,
|
||||
deps = filter(None, [x.get(SharedLibraryInfo) for x in deps]),
|
||||
)
|
||||
native_linkables = {so_name: shared_lib for so_name, shared_lib in traverse_shared_library_info(shared_library_info).items() if shared_lib not in shared_libraries_to_exclude}
|
||||
all_shared_libraries.extend(native_linkables.values())
|
||||
unstripped_libs += [shared_lib.lib.output for shared_lib in native_linkables.values()]
|
||||
platform_to_native_linkables[platform] = native_linkables
|
||||
|
||||
if apk_module_graph_file == None:
|
||||
native_libs_and_assets_info = _get_native_libs_and_assets(
|
||||
ctx,
|
||||
all_targets_in_root_module,
|
||||
all_prebuilt_native_library_dirs,
|
||||
platform_to_native_linkables,
|
||||
)
|
||||
native_libs_for_primary_apk, exopackage_info = _get_exopackage_info(
|
||||
ctx,
|
||||
native_libs_and_assets_info.native_libs_always_in_primary_apk,
|
||||
native_libs_and_assets_info.native_libs,
|
||||
native_libs_and_assets_info.native_libs_metadata,
|
||||
)
|
||||
native_lib_assets = filter(None, [
|
||||
native_libs_and_assets_info.native_lib_assets_for_primary_apk,
|
||||
native_libs_and_assets_info.stripped_native_linkable_assets_for_primary_apk,
|
||||
native_libs_and_assets_info.metadata_assets,
|
||||
native_libs_and_assets_info.compressed_lib_assets,
|
||||
])
|
||||
return AndroidBinaryNativeLibsInfo(
|
||||
apk_under_test_prebuilt_native_library_dirs = all_prebuilt_native_library_dirs,
|
||||
apk_under_test_shared_libraries = all_shared_libraries,
|
||||
native_libs_for_primary_apk = native_libs_for_primary_apk,
|
||||
exopackage_info = exopackage_info,
|
||||
unstripped_libs = unstripped_libs,
|
||||
native_lib_assets = native_lib_assets,
|
||||
)
|
||||
else:
|
||||
native_libs = ctx.actions.declare_output("native_libs_symlink")
|
||||
native_libs_metadata = ctx.actions.declare_output("native_libs_metadata_symlink")
|
||||
native_libs_always_in_primary_apk = ctx.actions.declare_output("native_libs_always_in_primary_apk_symlink")
|
||||
native_lib_assets_for_primary_apk = ctx.actions.declare_output("native_lib_assets_for_primary_apk_symlink")
|
||||
stripped_native_linkable_assets_for_primary_apk = ctx.actions.declare_output("stripped_native_linkable_assets_for_primary_apk_symlink")
|
||||
metadata_assets = ctx.actions.declare_output("metadata_assets_symlink")
|
||||
compressed_lib_assets = ctx.actions.declare_output("compressed_lib_assets_symlink")
|
||||
|
||||
outputs = [
|
||||
native_libs,
|
||||
native_libs_metadata,
|
||||
native_libs_always_in_primary_apk,
|
||||
native_lib_assets_for_primary_apk,
|
||||
stripped_native_linkable_assets_for_primary_apk,
|
||||
metadata_assets,
|
||||
compressed_lib_assets,
|
||||
]
|
||||
|
||||
def get_native_libs_info_modular(ctx: "context", artifacts, outputs):
|
||||
get_module_from_target = get_apk_module_graph_info(ctx, apk_module_graph_file, artifacts).target_to_module_mapping_function
|
||||
dynamic_info = _get_native_libs_and_assets(
|
||||
ctx,
|
||||
get_module_from_target,
|
||||
all_prebuilt_native_library_dirs,
|
||||
platform_to_native_linkables,
|
||||
)
|
||||
|
||||
# Since we are using a dynamic action, we need to declare the outputs in advance.
|
||||
# Rather than passing the created outputs into `_get_native_libs_and_assets`, we
|
||||
# just symlink to the outputs that function produces.
|
||||
ctx.actions.symlink_file(outputs[native_libs], dynamic_info.native_libs)
|
||||
ctx.actions.symlink_file(outputs[native_libs_metadata], dynamic_info.native_libs_metadata)
|
||||
ctx.actions.symlink_file(outputs[native_libs_always_in_primary_apk], dynamic_info.native_libs_always_in_primary_apk)
|
||||
ctx.actions.symlink_file(outputs[native_lib_assets_for_primary_apk], dynamic_info.native_lib_assets_for_primary_apk if dynamic_info.native_lib_assets_for_primary_apk else ctx.actions.symlinked_dir("empty_native_lib_assets", {}))
|
||||
ctx.actions.symlink_file(outputs[stripped_native_linkable_assets_for_primary_apk], dynamic_info.stripped_native_linkable_assets_for_primary_apk if dynamic_info.stripped_native_linkable_assets_for_primary_apk else ctx.actions.symlinked_dir("empty_stripped_native_linkable_assets", {}))
|
||||
ctx.actions.symlink_file(outputs[metadata_assets], dynamic_info.metadata_assets)
|
||||
ctx.actions.symlink_file(outputs[compressed_lib_assets], dynamic_info.compressed_lib_assets)
|
||||
|
||||
ctx.actions.dynamic_output(dynamic = [apk_module_graph_file], inputs = [], outputs = outputs, f = get_native_libs_info_modular)
|
||||
|
||||
native_libs_for_primary_apk, exopackage_info = _get_exopackage_info(ctx, native_libs_always_in_primary_apk, native_libs, native_libs_metadata)
|
||||
return AndroidBinaryNativeLibsInfo(
|
||||
apk_under_test_prebuilt_native_library_dirs = all_prebuilt_native_library_dirs,
|
||||
apk_under_test_shared_libraries = all_shared_libraries,
|
||||
native_libs_for_primary_apk = native_libs_for_primary_apk,
|
||||
exopackage_info = exopackage_info,
|
||||
unstripped_libs = unstripped_libs,
|
||||
native_lib_assets = [native_lib_assets_for_primary_apk, stripped_native_linkable_assets_for_primary_apk, metadata_assets, compressed_lib_assets],
|
||||
)
|
||||
|
||||
# We could just return two artifacts of libs (one for the primary APK, one which can go
|
||||
# either into the primary APK or be exopackaged), and one artifact of assets,
|
||||
# but we'd need an extra action in order to combine them (we can't use `symlinked_dir` since
|
||||
# the paths overlap) so it's easier to just be explicit about exactly what we produce.
|
||||
_NativeLibsAndAssetsInfo = record(
|
||||
native_libs = "artifact",
|
||||
native_libs_metadata = "artifact",
|
||||
native_libs_always_in_primary_apk = "artifact",
|
||||
native_lib_assets_for_primary_apk = ["artifact", None],
|
||||
stripped_native_linkable_assets_for_primary_apk = ["artifact", None],
|
||||
metadata_assets = "artifact",
|
||||
compressed_lib_assets = "artifact",
|
||||
)
|
||||
|
||||
def _get_exopackage_info(
|
||||
ctx: "context",
|
||||
native_libs_always_in_primary_apk: "artifact",
|
||||
native_libs: "artifact",
|
||||
native_libs_metadata: "artifact") -> (["artifact"], [ExopackageNativeInfo.type, None]):
|
||||
is_exopackage_enabled_for_native_libs = "native_library" in getattr(ctx.attrs, "exopackage_modes", [])
|
||||
if is_exopackage_enabled_for_native_libs:
|
||||
return [native_libs_always_in_primary_apk], ExopackageNativeInfo(directory = native_libs, metadata = native_libs_metadata)
|
||||
else:
|
||||
return [native_libs, native_libs_always_in_primary_apk], None
|
||||
|
||||
def _get_native_libs_and_assets(
|
||||
ctx: "context",
|
||||
get_module_from_target: "function",
|
||||
all_prebuilt_native_library_dirs: ["PrebuiltNativeLibraryDir"],
|
||||
platform_to_native_linkables: {str.type: {str.type: "SharedLibrary"}}) -> _NativeLibsAndAssetsInfo.type:
|
||||
is_packaging_native_libs_as_assets_supported = getattr(ctx.attrs, "package_asset_libraries", False)
|
||||
|
||||
prebuilt_native_library_dirs = []
|
||||
prebuilt_native_library_dirs_always_in_primary_apk = []
|
||||
prebuilt_native_library_dir_assets_for_primary_apk = []
|
||||
prebuilt_native_library_dir_module_assets_map = {}
|
||||
for native_lib in all_prebuilt_native_library_dirs:
|
||||
native_lib_target = str(native_lib.raw_target)
|
||||
module = get_module_from_target(native_lib_target)
|
||||
if not is_root_module(module):
|
||||
# In buck1, we always package native libs as assets when they are not in the root module
|
||||
expect(not native_lib.for_primary_apk, "{} which is marked as needing to be in the primary APK cannot be included in non-root-module {}".format(native_lib_target, module))
|
||||
prebuilt_native_library_dir_module_assets_map.setdefault(module, []).append(native_lib)
|
||||
elif native_lib.is_asset and is_packaging_native_libs_as_assets_supported:
|
||||
expect(not native_lib.for_primary_apk, "{} which is marked as needing to be in the primary APK cannot be an asset".format(native_lib_target))
|
||||
prebuilt_native_library_dir_assets_for_primary_apk.append(native_lib)
|
||||
elif native_lib.for_primary_apk:
|
||||
prebuilt_native_library_dirs_always_in_primary_apk.append(native_lib)
|
||||
else:
|
||||
prebuilt_native_library_dirs.append(native_lib)
|
||||
|
||||
native_libs = _filter_prebuilt_native_library_dir(
|
||||
ctx,
|
||||
prebuilt_native_library_dirs,
|
||||
"native_libs",
|
||||
)
|
||||
native_libs_always_in_primary_apk = _filter_prebuilt_native_library_dir(
|
||||
ctx,
|
||||
prebuilt_native_library_dirs_always_in_primary_apk,
|
||||
"native_libs_always_in_primary_apk",
|
||||
)
|
||||
native_lib_assets_for_primary_apk = _filter_prebuilt_native_library_dir(
|
||||
ctx,
|
||||
prebuilt_native_library_dir_assets_for_primary_apk,
|
||||
"native_lib_assets_for_primary_apk",
|
||||
package_as_assets = True,
|
||||
module = ROOT_MODULE,
|
||||
) if prebuilt_native_library_dir_assets_for_primary_apk else None
|
||||
native_lib_module_assets_map = {}
|
||||
for module, native_lib_dir in prebuilt_native_library_dir_module_assets_map.items():
|
||||
native_lib_module_assets_map[module] = [_filter_prebuilt_native_library_dir(
|
||||
ctx,
|
||||
native_lib_dir,
|
||||
"native_lib_assets_for_module_{}".format(module),
|
||||
package_as_assets = True,
|
||||
module = module,
|
||||
)]
|
||||
|
||||
(
|
||||
stripped_native_linkables,
|
||||
stripped_native_linkables_always_in_primary_apk,
|
||||
stripped_native_linkable_assets_for_primary_apk,
|
||||
stripped_native_linkable_module_assets_map,
|
||||
) = _get_native_linkables(ctx, platform_to_native_linkables, get_module_from_target, is_packaging_native_libs_as_assets_supported)
|
||||
for module, native_linkable_assets in stripped_native_linkable_module_assets_map.items():
|
||||
native_lib_module_assets_map.setdefault(module, []).append(native_linkable_assets)
|
||||
|
||||
metadata_srcs = {}
|
||||
compressed_lib_srcs = {}
|
||||
assets_for_primary_apk = filter(None, [native_lib_assets_for_primary_apk, stripped_native_linkable_assets_for_primary_apk])
|
||||
if assets_for_primary_apk:
|
||||
metadata_file, native_library_paths = _get_native_libs_as_assets_metadata(ctx, assets_for_primary_apk, ROOT_MODULE)
|
||||
metadata_srcs[paths.join(_get_native_libs_as_assets_dir(ROOT_MODULE), "metadata.txt")] = metadata_file
|
||||
if ctx.attrs.compress_asset_libraries:
|
||||
compressed_lib_dir = _get_compressed_native_libs_as_assets(ctx, assets_for_primary_apk, native_library_paths, ROOT_MODULE)
|
||||
compressed_lib_srcs[_get_native_libs_as_assets_dir(ROOT_MODULE)] = compressed_lib_dir
|
||||
|
||||
# Since we're storing these as compressed assets, we need to ignore the uncompressed libs.
|
||||
native_lib_assets_for_primary_apk = None
|
||||
stripped_native_linkable_assets_for_primary_apk = None
|
||||
|
||||
for module, native_lib_assets in native_lib_module_assets_map.items():
|
||||
metadata_file, native_library_paths = _get_native_libs_as_assets_metadata(ctx, native_lib_assets, module)
|
||||
metadata_srcs[paths.join(_get_native_libs_as_assets_dir(module), "libs.txt")] = metadata_file
|
||||
compressed_lib_dir = _get_compressed_native_libs_as_assets(ctx, native_lib_assets, native_library_paths, module)
|
||||
compressed_lib_srcs[_get_native_libs_as_assets_dir(module)] = compressed_lib_dir
|
||||
|
||||
combined_native_libs = ctx.actions.declare_output("combined_native_libs")
|
||||
native_libs_metadata = ctx.actions.declare_output("native_libs_metadata.txt")
|
||||
ctx.actions.run(cmd_args([
|
||||
ctx.attrs._android_toolchain[AndroidToolchainInfo].combine_native_library_dirs[RunInfo],
|
||||
"--output-dir",
|
||||
combined_native_libs.as_output(),
|
||||
"--library-dirs",
|
||||
native_libs,
|
||||
stripped_native_linkables,
|
||||
"--metadata-file",
|
||||
native_libs_metadata.as_output(),
|
||||
]), category = "combine_native_libs")
|
||||
|
||||
combined_native_libs_always_in_primary_apk = ctx.actions.declare_output("combined_native_libs_always_in_primary_apk")
|
||||
ctx.actions.run(cmd_args([
|
||||
ctx.attrs._android_toolchain[AndroidToolchainInfo].combine_native_library_dirs[RunInfo],
|
||||
"--output-dir",
|
||||
combined_native_libs_always_in_primary_apk.as_output(),
|
||||
"--library-dirs",
|
||||
native_libs_always_in_primary_apk,
|
||||
stripped_native_linkables_always_in_primary_apk,
|
||||
]), category = "combine_native_libs_always_in_primary_apk")
|
||||
|
||||
return _NativeLibsAndAssetsInfo(
|
||||
native_libs = combined_native_libs,
|
||||
native_libs_metadata = native_libs_metadata,
|
||||
native_libs_always_in_primary_apk = combined_native_libs_always_in_primary_apk,
|
||||
native_lib_assets_for_primary_apk = native_lib_assets_for_primary_apk,
|
||||
stripped_native_linkable_assets_for_primary_apk = stripped_native_linkable_assets_for_primary_apk,
|
||||
metadata_assets = ctx.actions.symlinked_dir("metadata_assets", metadata_srcs),
|
||||
compressed_lib_assets = ctx.actions.symlinked_dir("compressed_lib_assets", compressed_lib_srcs),
|
||||
)
|
||||
|
||||
def _filter_prebuilt_native_library_dir(
|
||||
ctx: "context",
|
||||
native_libs: ["PrebuiltNativeLibraryDir"],
|
||||
identifier: str.type,
|
||||
package_as_assets: bool.type = False,
|
||||
module: str.type = ROOT_MODULE) -> "artifact":
|
||||
cpu_filters = ctx.attrs.cpu_filters or CPU_FILTER_TO_ABI_DIRECTORY.keys()
|
||||
abis = [CPU_FILTER_TO_ABI_DIRECTORY[cpu] for cpu in cpu_filters]
|
||||
filter_tool = ctx.attrs._android_toolchain[AndroidToolchainInfo].filter_prebuilt_native_library_dir[RunInfo]
|
||||
native_libs_dirs = [native_lib.dir for native_lib in native_libs]
|
||||
native_libs_dirs_file = ctx.actions.write("{}_list.txt".format(identifier), native_libs_dirs)
|
||||
base_output_dir = ctx.actions.declare_output(identifier)
|
||||
output_dir = base_output_dir.project(_get_native_libs_as_assets_dir(module)) if package_as_assets else base_output_dir
|
||||
ctx.actions.run(
|
||||
cmd_args([filter_tool, native_libs_dirs_file, output_dir.as_output(), "--abis"] + abis).hidden(native_libs_dirs),
|
||||
category = "filter_prebuilt_native_library_dir",
|
||||
identifier = identifier,
|
||||
)
|
||||
|
||||
return base_output_dir
|
||||
|
||||
def _get_native_linkables(
|
||||
ctx: "context",
|
||||
platform_to_native_linkables: {str.type: {str.type: "SharedLibrary"}},
|
||||
get_module_from_target: "function",
|
||||
package_native_libs_as_assets_enabled: bool.type) -> ("artifact", "artifact", ["artifact", None], {str.type: "artifact"}):
|
||||
stripped_native_linkables_srcs = {}
|
||||
stripped_native_linkables_always_in_primary_apk_srcs = {}
|
||||
stripped_native_linkable_assets_for_primary_apk_srcs = {}
|
||||
stripped_native_linkable_module_assets_srcs = {}
|
||||
|
||||
cpu_filters = ctx.attrs.cpu_filters
|
||||
for platform, native_linkables in platform_to_native_linkables.items():
|
||||
if cpu_filters and platform not in cpu_filters:
|
||||
fail("Platform `{}` is not in the CPU filters `{}`".format(platform, cpu_filters))
|
||||
|
||||
abi_directory = CPU_FILTER_TO_ABI_DIRECTORY[platform]
|
||||
for so_name, native_linkable in native_linkables.items():
|
||||
native_linkable_target = str(native_linkable.label.raw_target())
|
||||
module = get_module_from_target(native_linkable_target)
|
||||
|
||||
if not is_root_module(module):
|
||||
expect(not native_linkable.for_primary_apk, "{} which is marked as needing to be in the primary APK cannot be included in non-root-module {}".format(native_linkable_target, module))
|
||||
so_name_path = paths.join(_get_native_libs_as_assets_dir(module), abi_directory, so_name)
|
||||
stripped_native_linkable_module_assets_srcs.setdefault(module, {})[so_name_path] = native_linkable.stripped_lib
|
||||
elif native_linkable.can_be_asset and package_native_libs_as_assets_enabled:
|
||||
expect(not native_linkable.for_primary_apk, "{} which is marked as needing to be in the primary APK cannot be an asset".format(native_linkable_target))
|
||||
so_name_path = paths.join(_get_native_libs_as_assets_dir(module), abi_directory, so_name)
|
||||
stripped_native_linkable_assets_for_primary_apk_srcs[so_name_path] = native_linkable.stripped_lib
|
||||
else:
|
||||
so_name_path = paths.join(abi_directory, so_name)
|
||||
if native_linkable.for_primary_apk:
|
||||
stripped_native_linkables_always_in_primary_apk_srcs[so_name_path] = native_linkable.stripped_lib
|
||||
else:
|
||||
stripped_native_linkables_srcs[so_name_path] = native_linkable.stripped_lib
|
||||
|
||||
stripped_native_linkables = ctx.actions.symlinked_dir(
|
||||
"stripped_native_linkables",
|
||||
stripped_native_linkables_srcs,
|
||||
)
|
||||
stripped_native_linkables_always_in_primary_apk = ctx.actions.symlinked_dir(
|
||||
"stripped_native_linkables_always_in_primary_apk",
|
||||
stripped_native_linkables_always_in_primary_apk_srcs,
|
||||
)
|
||||
stripped_native_linkable_assets_for_primary_apk = ctx.actions.symlinked_dir(
|
||||
"stripped_native_linkables_assets_for_primary_apk",
|
||||
stripped_native_linkable_assets_for_primary_apk_srcs,
|
||||
) if stripped_native_linkable_assets_for_primary_apk_srcs else None
|
||||
stripped_native_linkable_module_assets_map = {}
|
||||
for module, srcs in stripped_native_linkable_module_assets_srcs.items():
|
||||
stripped_native_linkable_module_assets_map[module] = ctx.actions.symlinked_dir(
|
||||
"stripped_native_linkable_assets_for_module_{}".format(module),
|
||||
srcs,
|
||||
)
|
||||
|
||||
return (
|
||||
stripped_native_linkables,
|
||||
stripped_native_linkables_always_in_primary_apk,
|
||||
stripped_native_linkable_assets_for_primary_apk,
|
||||
stripped_native_linkable_module_assets_map,
|
||||
)
|
||||
|
||||
def _get_native_libs_as_assets_metadata(
|
||||
ctx: "context",
|
||||
native_lib_assets: ["artifact"],
|
||||
module: str.type) -> ("artifact", "artifact"):
|
||||
native_lib_assets_file = ctx.actions.write("{}/native_lib_assets".format(module), [cmd_args([native_lib_asset, _get_native_libs_as_assets_dir(module)], delimiter = "/") for native_lib_asset in native_lib_assets])
|
||||
metadata_output = ctx.actions.declare_output("{}/native_libs_as_assets_metadata.txt".format(module))
|
||||
native_library_paths = ctx.actions.declare_output("{}/native_libs_as_assets_paths.txt".format(module))
|
||||
metadata_cmd = cmd_args([
|
||||
ctx.attrs._android_toolchain[AndroidToolchainInfo].native_libs_as_assets_metadata[RunInfo],
|
||||
"--native-library-dirs",
|
||||
native_lib_assets_file,
|
||||
"--metadata-output",
|
||||
metadata_output.as_output(),
|
||||
"--native-library-paths-output",
|
||||
native_library_paths.as_output(),
|
||||
]).hidden(native_lib_assets)
|
||||
ctx.actions.run(metadata_cmd, category = "get_native_libs_as_assets_metadata", identifier = module)
|
||||
return metadata_output, native_library_paths
|
||||
|
||||
def _get_compressed_native_libs_as_assets(
|
||||
ctx: "context",
|
||||
native_lib_assets: ["artifact"],
|
||||
native_library_paths: "artifact",
|
||||
module: str.type) -> "artifact":
|
||||
output_dir = ctx.actions.declare_output("{}/compressed_native_libs_as_assets_dir".format(module))
|
||||
compressed_libraries_cmd = cmd_args([
|
||||
ctx.attrs._android_toolchain[AndroidToolchainInfo].compress_libraries[RunInfo],
|
||||
"--libraries",
|
||||
native_library_paths,
|
||||
"--output-dir",
|
||||
output_dir.as_output(),
|
||||
"--compression-type",
|
||||
ctx.attrs.asset_compression_algorithm or "xz",
|
||||
"--xz-compression-level",
|
||||
str(ctx.attrs.xz_compression_level),
|
||||
]).hidden(native_lib_assets)
|
||||
ctx.actions.run(compressed_libraries_cmd, category = "compress_native_libs_as_assets", identifier = module)
|
||||
return output_dir
|
||||
|
||||
def _get_native_libs_as_assets_dir(module: str.type) -> str.type:
|
||||
return "assets/{}".format("lib" if is_root_module(module) else module)
|
||||
473
vendor/cxx/tools/buck/prelude/android/android_binary_resources_rules.bzl
vendored
Normal file
473
vendor/cxx/tools/buck/prelude/android/android_binary_resources_rules.bzl
vendored
Normal file
|
|
@ -0,0 +1,473 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load("@prelude//:attributes.bzl", "RType")
|
||||
load("@prelude//:resources.bzl", "gather_resources")
|
||||
load("@prelude//android:aapt2_link.bzl", "get_aapt2_link")
|
||||
load("@prelude//android:android_manifest.bzl", "generate_android_manifest")
|
||||
load("@prelude//android:android_providers.bzl", "AndroidBinaryResourcesInfo", "AndroidResourceInfo", "ExopackageResourcesInfo")
|
||||
load("@prelude//android:android_resource.bzl", "aapt2_compile")
|
||||
load("@prelude//android:android_toolchain.bzl", "AndroidToolchainInfo")
|
||||
load("@prelude//android:r_dot_java.bzl", "generate_r_dot_javas")
|
||||
load("@prelude//java:java_toolchain.bzl", "JavaToolchainInfo")
|
||||
load("@prelude//utils:utils.bzl", "expect")
|
||||
|
||||
def get_android_binary_resources_info(
|
||||
ctx: "context",
|
||||
deps: ["dependency"],
|
||||
android_packageable_info: "AndroidPackageableInfo",
|
||||
java_packaging_deps: ["JavaPackagingDep"],
|
||||
use_proto_format: bool.type,
|
||||
referenced_resources_lists: ["artifact"],
|
||||
manifest_entries: dict.type = {},
|
||||
resource_infos_to_exclude: [AndroidResourceInfo.type] = []) -> "AndroidBinaryResourcesInfo":
|
||||
android_toolchain = ctx.attrs._android_toolchain[AndroidToolchainInfo]
|
||||
unfiltered_resource_infos = [resource_info for resource_info in list(android_packageable_info.resource_infos.traverse() if android_packageable_info.resource_infos else []) if resource_info not in resource_infos_to_exclude]
|
||||
resource_infos, override_symbols, string_files_list, string_files_res_dirs = _maybe_filter_resources(
|
||||
ctx,
|
||||
unfiltered_resource_infos,
|
||||
android_toolchain,
|
||||
)
|
||||
|
||||
android_manifest = _get_manifest(ctx, android_packageable_info, manifest_entries)
|
||||
|
||||
aapt2_link_info = get_aapt2_link(
|
||||
ctx,
|
||||
ctx.attrs._android_toolchain[AndroidToolchainInfo],
|
||||
[resource_info.aapt2_compile_output for resource_info in resource_infos if resource_info.aapt2_compile_output != None],
|
||||
android_manifest,
|
||||
includes_vector_drawables = getattr(ctx.attrs, "includes_vector_drawables", False),
|
||||
no_auto_version = getattr(ctx.attrs, "no_auto_version_resources", False),
|
||||
no_version_transitions = getattr(ctx.attrs, "no_version_transitions_resources", False),
|
||||
no_auto_add_overlay = getattr(ctx.attrs, "no_auto_add_overlay_resources", False),
|
||||
use_proto_format = use_proto_format,
|
||||
no_resource_removal = True,
|
||||
package_id_offset = 0,
|
||||
should_keep_raw_values = getattr(ctx.attrs, "aapt2_keep_raw_values", False),
|
||||
resource_stable_ids = getattr(ctx.attrs, "resource_stable_ids", None),
|
||||
compiled_resource_apks = [],
|
||||
additional_aapt2_params = getattr(ctx.attrs, "additional_aapt_params", []),
|
||||
extra_filtered_resources = getattr(ctx.attrs, "extra_filtered_resources", []),
|
||||
locales = getattr(ctx.attrs, "locales", []),
|
||||
filter_locales = getattr(ctx.attrs, "aapt2_locale_filtering", False),
|
||||
)
|
||||
|
||||
prebuilt_jars = [packaging_dep.jar for packaging_dep in java_packaging_deps if packaging_dep.is_prebuilt_jar]
|
||||
|
||||
cxx_resources = _get_cxx_resources(ctx, deps)
|
||||
is_exopackaged_enabled_for_resources = "resources" in getattr(ctx.attrs, "exopackage_modes", [])
|
||||
primary_resources_apk, exopackaged_assets, exopackaged_assets_hash = _merge_assets(
|
||||
ctx,
|
||||
is_exopackaged_enabled_for_resources,
|
||||
aapt2_link_info.primary_resources_apk,
|
||||
resource_infos,
|
||||
cxx_resources,
|
||||
)
|
||||
|
||||
if is_exopackaged_enabled_for_resources:
|
||||
r_dot_txt = ctx.actions.declare_output("after_exo/R.txt")
|
||||
primary_resources_apk = ctx.actions.declare_output("after_exo/primary_resources_apk.apk")
|
||||
exo_resources = ctx.actions.declare_output("exo_resources.apk")
|
||||
exo_resources_hash = ctx.actions.declare_output("exo_resources.apk.hash")
|
||||
ctx.actions.run(cmd_args([
|
||||
android_toolchain.exo_resources_rewriter[RunInfo],
|
||||
"--original-r-dot-txt",
|
||||
aapt2_link_info.r_dot_txt,
|
||||
"--new-r-dot-txt",
|
||||
r_dot_txt.as_output(),
|
||||
"--original-primary-apk-resources",
|
||||
aapt2_link_info.primary_resources_apk,
|
||||
"--new-primary-apk-resources",
|
||||
primary_resources_apk.as_output(),
|
||||
"--exo-resources",
|
||||
exo_resources.as_output(),
|
||||
"--exo-resources-hash",
|
||||
exo_resources_hash.as_output(),
|
||||
"--zipalign-tool",
|
||||
android_toolchain.zipalign[RunInfo],
|
||||
]), category = "write_exo_resources")
|
||||
|
||||
third_party_jars = ctx.actions.write("third_party_jars", prebuilt_jars)
|
||||
third_party_jar_resources = ctx.actions.declare_output("third_party_jars.resources")
|
||||
third_party_jar_resources_hash = ctx.actions.declare_output("third_party_jars.resources.hash")
|
||||
ctx.actions.run(cmd_args([
|
||||
android_toolchain.merge_third_party_jar_resources[RunInfo],
|
||||
"--output",
|
||||
third_party_jar_resources.as_output(),
|
||||
"--output-hash",
|
||||
third_party_jar_resources_hash.as_output(),
|
||||
"--third-party-jars",
|
||||
third_party_jars,
|
||||
]).hidden(prebuilt_jars), category = "merge_third_party_jar_resources")
|
||||
|
||||
exopackage_info = ExopackageResourcesInfo(
|
||||
assets = exopackaged_assets,
|
||||
assets_hash = exopackaged_assets_hash,
|
||||
res = exo_resources,
|
||||
res_hash = exo_resources_hash,
|
||||
third_party_jar_resources = third_party_jar_resources,
|
||||
third_party_jar_resources_hash = third_party_jar_resources_hash,
|
||||
)
|
||||
jar_files_that_may_contain_resources = []
|
||||
else:
|
||||
exopackage_info = None
|
||||
jar_files_that_may_contain_resources = prebuilt_jars
|
||||
r_dot_txt = aapt2_link_info.r_dot_txt
|
||||
|
||||
override_symbols_paths = [override_symbols] if override_symbols else []
|
||||
resources = [resource for resource in resource_infos if resource.res != None]
|
||||
r_dot_javas = [] if len(resources) == 0 else generate_r_dot_javas(
|
||||
ctx,
|
||||
ctx.attrs._android_toolchain[AndroidToolchainInfo].merge_android_resources[RunInfo],
|
||||
ctx.attrs._java_toolchain[JavaToolchainInfo],
|
||||
resources,
|
||||
get_effective_banned_duplicate_resource_types(
|
||||
getattr(ctx.attrs, "duplicate_resource_behavior", "allow_by_default"),
|
||||
getattr(ctx.attrs, "allowed_duplicate_resource_types", []),
|
||||
getattr(ctx.attrs, "banned_duplicate_resource_types", []),
|
||||
),
|
||||
[r_dot_txt],
|
||||
override_symbols_paths,
|
||||
getattr(ctx.attrs, "duplicate_resource_whitelist", None),
|
||||
getattr(ctx.attrs, "resource_union_package", None),
|
||||
referenced_resources_lists,
|
||||
)
|
||||
string_source_map = _maybe_generate_string_source_map(
|
||||
ctx.actions,
|
||||
getattr(ctx.attrs, "build_string_source_map", False),
|
||||
resources,
|
||||
android_toolchain,
|
||||
)
|
||||
packaged_string_assets = _maybe_package_strings_as_assets(
|
||||
ctx,
|
||||
string_files_list,
|
||||
string_files_res_dirs,
|
||||
r_dot_txt,
|
||||
android_toolchain,
|
||||
)
|
||||
|
||||
return AndroidBinaryResourcesInfo(
|
||||
exopackage_info = exopackage_info,
|
||||
manifest = android_manifest,
|
||||
packaged_string_assets = packaged_string_assets,
|
||||
primary_resources_apk = primary_resources_apk,
|
||||
proguard_config_file = aapt2_link_info.proguard_config_file,
|
||||
r_dot_javas = r_dot_javas,
|
||||
string_source_map = string_source_map,
|
||||
jar_files_that_may_contain_resources = jar_files_that_may_contain_resources,
|
||||
unfiltered_resource_infos = unfiltered_resource_infos,
|
||||
)
|
||||
|
||||
def _maybe_filter_resources(
|
||||
ctx: "context",
|
||||
resources: [AndroidResourceInfo.type],
|
||||
android_toolchain: AndroidToolchainInfo.type) -> ([AndroidResourceInfo.type], ["artifact", None], ["artifact", None], ["artifact"]):
|
||||
resources_filter_strings = getattr(ctx.attrs, "resource_filter", [])
|
||||
resources_filter = _get_resources_filter(resources_filter_strings)
|
||||
resource_compression_mode = getattr(ctx.attrs, "resource_compression", "disabled")
|
||||
is_store_strings_as_assets = _is_store_strings_as_assets(resource_compression_mode)
|
||||
locales = getattr(ctx.attrs, "locales", None)
|
||||
use_aapt2_locale_filtering = getattr(ctx.attrs, "aapt2_locale_filtering", False)
|
||||
needs_resource_filtering_for_locales = locales != None and len(locales) > 0 and not use_aapt2_locale_filtering
|
||||
post_filter_resources_cmd = getattr(ctx.attrs, "post_filter_resources_cmd", None)
|
||||
|
||||
needs_resource_filtering = (
|
||||
resources_filter != None or
|
||||
is_store_strings_as_assets or
|
||||
needs_resource_filtering_for_locales or
|
||||
post_filter_resources_cmd != None
|
||||
)
|
||||
|
||||
if not needs_resource_filtering:
|
||||
return resources, None, None, []
|
||||
|
||||
res_info_to_out_res_dir = {}
|
||||
res_infos_with_no_res = []
|
||||
skip_crunch_pngs = getattr(ctx.attrs, "skip_crunch_pngs", None) or False
|
||||
for i, resource in enumerate(resources):
|
||||
if resource.res == None:
|
||||
res_infos_with_no_res.append(resource)
|
||||
else:
|
||||
filtered_res = ctx.actions.declare_output("filtered_res_{}".format(i))
|
||||
res_info_to_out_res_dir[resource] = filtered_res
|
||||
|
||||
filter_resources_cmd = cmd_args(android_toolchain.filter_resources[RunInfo])
|
||||
in_res_dir_to_out_res_dir_dict = {
|
||||
in_res.res: out_res
|
||||
for in_res, out_res in res_info_to_out_res_dir.items()
|
||||
}
|
||||
in_res_dir_to_out_res_dir_map = ctx.actions.write_json("in_res_dir_to_out_res_dir_map", {"res_dir_map": in_res_dir_to_out_res_dir_dict})
|
||||
in_res_dirs = [in_res.res for in_res in res_info_to_out_res_dir.keys()]
|
||||
filter_resources_cmd.hidden(in_res_dirs)
|
||||
filter_resources_cmd.hidden([out_res.as_output() for out_res in res_info_to_out_res_dir.values()])
|
||||
filter_resources_cmd.add([
|
||||
"--in-res-dir-to-out-res-dir-map",
|
||||
in_res_dir_to_out_res_dir_map,
|
||||
])
|
||||
|
||||
if resources_filter:
|
||||
filter_resources_cmd.add([
|
||||
"--target-densities",
|
||||
",".join(resources_filter.densities),
|
||||
])
|
||||
|
||||
all_strings_files_list = None
|
||||
all_strings_files_res_dirs = []
|
||||
if is_store_strings_as_assets:
|
||||
all_strings_files_list = ctx.actions.declare_output("all_strings_files")
|
||||
all_strings_files_res_dirs = in_res_dirs
|
||||
filter_resources_cmd.add([
|
||||
"--enable-string-as-assets-filtering",
|
||||
"--string-files-list-output",
|
||||
all_strings_files_list.as_output(),
|
||||
])
|
||||
|
||||
packaged_locales = getattr(ctx.attrs, "packaged_locales", [])
|
||||
if packaged_locales:
|
||||
filter_resources_cmd.add([
|
||||
"--packaged-locales",
|
||||
",".join(packaged_locales),
|
||||
])
|
||||
|
||||
not_filtered_string_dirs = [resource.res for resource in resources if not resource.allow_strings_as_assets_resource_filtering]
|
||||
if not_filtered_string_dirs:
|
||||
filter_resources_cmd.add([
|
||||
"--not-filtered-string-dirs",
|
||||
ctx.actions.write("not_filtered_string_dirs", not_filtered_string_dirs),
|
||||
])
|
||||
|
||||
if needs_resource_filtering_for_locales:
|
||||
filter_resources_cmd.add([
|
||||
"--locales",
|
||||
",".join(locales),
|
||||
])
|
||||
|
||||
override_symbols_artifact = None
|
||||
if post_filter_resources_cmd != None:
|
||||
override_symbols_artifact = ctx.actions.declare_output("post_filter_resources_cmd/R.json")
|
||||
filter_resources_cmd.add([
|
||||
"--post-filter-resources-cmd",
|
||||
post_filter_resources_cmd,
|
||||
"--post-filter-resources-cmd-override-symbols-output",
|
||||
override_symbols_artifact.as_output(),
|
||||
])
|
||||
|
||||
ctx.actions.run(filter_resources_cmd, category = "filter_resources")
|
||||
|
||||
filtered_resource_infos = []
|
||||
for i, resource in enumerate(resources):
|
||||
if resource.res == None:
|
||||
continue
|
||||
|
||||
filtered_res = res_info_to_out_res_dir[resource]
|
||||
filtered_aapt2_compile_output = aapt2_compile(
|
||||
ctx,
|
||||
filtered_res,
|
||||
android_toolchain,
|
||||
skip_crunch_pngs = skip_crunch_pngs,
|
||||
identifier = "filtered_res_{}".format(i),
|
||||
)
|
||||
filtered_resource = AndroidResourceInfo(
|
||||
aapt2_compile_output = filtered_aapt2_compile_output,
|
||||
assets = resource.assets,
|
||||
manifest_file = resource.manifest_file,
|
||||
r_dot_java_package = resource.r_dot_java_package,
|
||||
res = filtered_res,
|
||||
text_symbols = resource.text_symbols,
|
||||
)
|
||||
filtered_resource_infos.append(filtered_resource)
|
||||
|
||||
return (
|
||||
res_infos_with_no_res + filtered_resource_infos,
|
||||
override_symbols_artifact,
|
||||
all_strings_files_list,
|
||||
all_strings_files_res_dirs,
|
||||
)
|
||||
|
||||
ResourcesFilter = record(
|
||||
densities = [str.type],
|
||||
downscale = bool.type,
|
||||
)
|
||||
|
||||
def _get_resources_filter(resources_filter_strings: [str.type]) -> [ResourcesFilter.type, None]:
|
||||
if not resources_filter_strings:
|
||||
return None
|
||||
|
||||
densities = [resources_filter_string for resources_filter_string in resources_filter_strings if resources_filter_string != "downscale"]
|
||||
if not densities:
|
||||
return None
|
||||
|
||||
downscale = len(densities) < len(resources_filter_strings)
|
||||
return ResourcesFilter(densities = densities, downscale = downscale)
|
||||
|
||||
def _maybe_generate_string_source_map(
|
||||
actions: "actions",
|
||||
should_build_source_string_map: bool.type,
|
||||
resource_infos: [AndroidResourceInfo.type],
|
||||
android_toolchain: AndroidToolchainInfo.type) -> ["artifact", None]:
|
||||
if not should_build_source_string_map or len(resource_infos) == 0:
|
||||
return None
|
||||
|
||||
res_dirs = [resource_info.res for resource_info in resource_infos]
|
||||
output = actions.declare_output("string_source_map")
|
||||
res_dirs_file = actions.write("resource_dirs_for_string_source_map", res_dirs)
|
||||
generate_string_source_map_cmd = cmd_args([
|
||||
android_toolchain.copy_string_resources[RunInfo],
|
||||
"--res-dirs",
|
||||
res_dirs_file,
|
||||
"--output",
|
||||
output.as_output(),
|
||||
]).hidden(res_dirs)
|
||||
|
||||
actions.run(generate_string_source_map_cmd, category = "generate_string_source_map")
|
||||
|
||||
return output
|
||||
|
||||
def _maybe_package_strings_as_assets(
|
||||
ctx: "context",
|
||||
string_files_list: ["artifact", None],
|
||||
string_files_res_dirs: ["artifact"],
|
||||
r_dot_txt: "artifact",
|
||||
android_toolchain: AndroidToolchainInfo.type) -> ["artifact", None]:
|
||||
resource_compression_mode = getattr(ctx.attrs, "resource_compression", "disabled")
|
||||
is_store_strings_as_assets = _is_store_strings_as_assets(resource_compression_mode)
|
||||
expect(is_store_strings_as_assets == (string_files_list != None))
|
||||
|
||||
if not is_store_strings_as_assets:
|
||||
return None
|
||||
|
||||
string_assets_dir = ctx.actions.declare_output("package_strings_as_assets/string_assets")
|
||||
string_assets_zip = ctx.actions.declare_output("package_strings_as_assets/string_assets_zip.zip")
|
||||
all_locales_string_assets_zip = ctx.actions.declare_output("package_strings_as_assets/all_locales_string_assets_zip.zip")
|
||||
|
||||
locales = getattr(ctx.attrs, "locales", [])
|
||||
|
||||
package_strings_as_assets_cmd = cmd_args([
|
||||
android_toolchain.package_strings_as_assets[RunInfo],
|
||||
"--string-files-list",
|
||||
string_files_list,
|
||||
"--r-dot-txt",
|
||||
r_dot_txt,
|
||||
"--string-assets-dir",
|
||||
string_assets_dir.as_output(),
|
||||
"--string-assets-zip",
|
||||
string_assets_zip.as_output(),
|
||||
"--all-locales-string-assets-zip",
|
||||
all_locales_string_assets_zip.as_output(),
|
||||
]).hidden(string_files_res_dirs)
|
||||
|
||||
if locales:
|
||||
package_strings_as_assets_cmd.add("--locales", ",".join(locales))
|
||||
|
||||
ctx.actions.run(package_strings_as_assets_cmd, category = "package_strings_as_assets")
|
||||
|
||||
return string_assets_zip
|
||||
|
||||
def _get_manifest(
|
||||
ctx: "context",
|
||||
android_packageable_info: "AndroidPackageableInfo",
|
||||
manifest_entries: dict.type) -> "artifact":
|
||||
robolectric_manifest = getattr(ctx.attrs, "robolectric_manifest", None)
|
||||
if robolectric_manifest:
|
||||
return robolectric_manifest
|
||||
|
||||
if ctx.attrs.manifest:
|
||||
expect(ctx.attrs.manifest_skeleton == None, "Only one of manifest and manifest_skeleton should be declared")
|
||||
if type(ctx.attrs.manifest) == "dependency":
|
||||
android_manifest = ctx.attrs.manifest[DefaultInfo].default_outputs[0]
|
||||
else:
|
||||
android_manifest = ctx.attrs.manifest
|
||||
else:
|
||||
expect(ctx.attrs.manifest_skeleton != None, "Must declare one of manifest and manifest_skeleton")
|
||||
if type(ctx.attrs.manifest_skeleton) == "dependency":
|
||||
manifest_skeleton = ctx.attrs.manifest_skeleton[DefaultInfo].default_outputs[0]
|
||||
else:
|
||||
manifest_skeleton = ctx.attrs.manifest_skeleton
|
||||
android_manifest, _ = generate_android_manifest(
|
||||
ctx,
|
||||
ctx.attrs._android_toolchain[AndroidToolchainInfo].generate_manifest[RunInfo],
|
||||
manifest_skeleton,
|
||||
"dex", # ROOT_APKMODULE_NAME,
|
||||
android_packageable_info.manifests,
|
||||
manifest_entries.get("placeholders", {}),
|
||||
)
|
||||
|
||||
return android_manifest
|
||||
|
||||
# Returns the "primary resources APK" (i.e. the resource that are packaged into the primary APK),
|
||||
# and optionally an "exopackaged assets APK" and the hash for that APK.
|
||||
def _merge_assets(
|
||||
ctx: "context",
|
||||
is_exopackaged_enabled_for_resources: bool.type,
|
||||
base_apk: "artifact",
|
||||
resource_infos: ["AndroidResourceInfo"],
|
||||
cxx_resources: ["artifact", None]) -> ("artifact", ["artifact", None], ["artifact", None]):
|
||||
assets_dirs = [resource_info.assets for resource_info in resource_infos if resource_info.assets]
|
||||
if cxx_resources != None:
|
||||
assets_dirs.extend([cxx_resources])
|
||||
if len(assets_dirs) == 0:
|
||||
return base_apk, None, None
|
||||
|
||||
merge_assets_cmd = cmd_args(ctx.attrs._android_toolchain[AndroidToolchainInfo].merge_assets[RunInfo])
|
||||
|
||||
merged_assets_output = ctx.actions.declare_output("merged_assets.ap_")
|
||||
merge_assets_cmd.add(["--output-apk", merged_assets_output.as_output()])
|
||||
|
||||
if is_exopackaged_enabled_for_resources:
|
||||
merged_assets_output_hash = ctx.actions.declare_output("merged_assets.ap_.hash")
|
||||
merge_assets_cmd.add(["--output-apk-hash", merged_assets_output_hash.as_output()])
|
||||
else:
|
||||
merge_assets_cmd.add(["--base-apk", base_apk])
|
||||
merged_assets_output_hash = None
|
||||
|
||||
assets_dirs_file = ctx.actions.write("assets_dirs", assets_dirs)
|
||||
merge_assets_cmd.add(["--assets-dirs", assets_dirs_file])
|
||||
merge_assets_cmd.hidden(assets_dirs)
|
||||
|
||||
ctx.actions.run(merge_assets_cmd, category = "merge_assets")
|
||||
|
||||
if is_exopackaged_enabled_for_resources:
|
||||
return base_apk, merged_assets_output, merged_assets_output_hash
|
||||
else:
|
||||
return merged_assets_output, None, None
|
||||
|
||||
def get_effective_banned_duplicate_resource_types(
|
||||
duplicate_resource_behavior: str.type,
|
||||
allowed_duplicate_resource_types: [str.type],
|
||||
banned_duplicate_resource_types: [str.type]) -> [str.type]:
|
||||
if duplicate_resource_behavior == "allow_by_default":
|
||||
expect(
|
||||
len(allowed_duplicate_resource_types) == 0,
|
||||
"Cannot set allowed_duplicate_resource_types if duplicate_resource_behaviour is allow_by_default",
|
||||
)
|
||||
return banned_duplicate_resource_types
|
||||
elif duplicate_resource_behavior == "ban_by_default":
|
||||
expect(
|
||||
len(banned_duplicate_resource_types) == 0,
|
||||
"Cannot set banned_duplicate_resource_types if duplicate_resource_behaviour is ban_by_default",
|
||||
)
|
||||
return [rtype for rtype in RType if rtype not in allowed_duplicate_resource_types]
|
||||
else:
|
||||
fail("Unrecognized duplicate_resource_behavior: {}".format(duplicate_resource_behavior))
|
||||
|
||||
def _get_cxx_resources(ctx: "context", deps: ["dependency"]) -> ["artifact", None]:
|
||||
cxx_resources = gather_resources(
|
||||
label = ctx.label,
|
||||
resources = {},
|
||||
deps = deps,
|
||||
)
|
||||
|
||||
symlink_tree_dict = {}
|
||||
resource_maps = cxx_resources.values()
|
||||
for resource_map in resource_maps:
|
||||
for name, (resource, _other) in resource_map.items():
|
||||
symlink_tree_dict["cxx-resources/{}".format(name)] = resource
|
||||
|
||||
return ctx.actions.symlinked_dir("cxx_resources_dir", symlink_tree_dict) if symlink_tree_dict else None
|
||||
|
||||
def _is_store_strings_as_assets(resource_compression: str.type) -> bool.type:
|
||||
return resource_compression == "enabled_strings_only" or resource_compression == "enabled_with_strings_as_assets"
|
||||
113
vendor/cxx/tools/buck/prelude/android/android_build_config.bzl
vendored
Normal file
113
vendor/cxx/tools/buck/prelude/android/android_build_config.bzl
vendored
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load("@prelude//android:android_toolchain.bzl", "AndroidToolchainInfo")
|
||||
load("@prelude//java:java_library.bzl", "compile_to_jar")
|
||||
load("@prelude//java:java_providers.bzl", "JavaLibraryInfo", "JavaPackagingDepTSet", "JavaPackagingInfo", "create_java_packaging_dep", "derive_compiling_deps")
|
||||
load(":android_providers.bzl", "AndroidBuildConfigInfo", "BuildConfigField", "merge_android_packageable_info")
|
||||
|
||||
def android_build_config_impl(ctx: "context") -> ["provider"]:
|
||||
providers = []
|
||||
|
||||
default_build_config_fields = get_build_config_fields(ctx.attrs.values)
|
||||
android_build_config_info = AndroidBuildConfigInfo(package = ctx.attrs.package, build_config_fields = default_build_config_fields)
|
||||
providers.append(android_build_config_info)
|
||||
providers.append(merge_android_packageable_info(ctx.label, ctx.actions, deps = [], build_config_info = android_build_config_info))
|
||||
|
||||
build_config_dot_java_library, java_packaging_info = generate_android_build_config(
|
||||
ctx,
|
||||
ctx.attrs.name,
|
||||
ctx.attrs.package,
|
||||
False,
|
||||
default_build_config_fields,
|
||||
ctx.attrs.values_file,
|
||||
)
|
||||
|
||||
providers.append(java_packaging_info)
|
||||
providers.append(build_config_dot_java_library)
|
||||
|
||||
providers.append(DefaultInfo(default_outputs = [build_config_dot_java_library.library_output.full_library]))
|
||||
return providers
|
||||
|
||||
def generate_android_build_config(
|
||||
ctx: "context",
|
||||
source: str.type,
|
||||
java_package: str.type,
|
||||
use_constant_expressions: bool.type,
|
||||
default_values: ["BuildConfigField"],
|
||||
values_file: ["artifact", None]) -> ("JavaLibraryInfo", "JavaPackagingInfo"):
|
||||
build_config_dot_java = _generate_build_config_dot_java(ctx, source, java_package, use_constant_expressions, default_values, values_file)
|
||||
|
||||
compiled_build_config_dot_java = _compile_and_package_build_config_dot_java(ctx, java_package, build_config_dot_java)
|
||||
library_output = compiled_build_config_dot_java.classpath_entry
|
||||
|
||||
packaging_deps_kwargs = {"value": create_java_packaging_dep(ctx, library_output.full_library)}
|
||||
packaging_deps = ctx.actions.tset(JavaPackagingDepTSet, **packaging_deps_kwargs)
|
||||
return (JavaLibraryInfo(
|
||||
compiling_deps = derive_compiling_deps(ctx.actions, library_output, []),
|
||||
library_output = library_output,
|
||||
output_for_classpath_macro = library_output.full_library,
|
||||
), JavaPackagingInfo(
|
||||
packaging_deps = packaging_deps,
|
||||
))
|
||||
|
||||
def _generate_build_config_dot_java(
|
||||
ctx: "context",
|
||||
source: str.type,
|
||||
java_package: str.type,
|
||||
use_constant_expressions: bool.type,
|
||||
default_values: ["BuildConfigField"],
|
||||
values_file: ["artifact", None]) -> "artifact":
|
||||
generate_build_config_cmd = cmd_args(ctx.attrs._android_toolchain[AndroidToolchainInfo].generate_build_config[RunInfo])
|
||||
generate_build_config_cmd.add([
|
||||
"--source",
|
||||
source,
|
||||
"--java-package",
|
||||
java_package,
|
||||
"--use-constant-expressions",
|
||||
str(use_constant_expressions),
|
||||
])
|
||||
|
||||
default_values_file = ctx.actions.write(
|
||||
_get_output_name(java_package, "default_values"),
|
||||
["{} {} = {}".format(x.type, x.name, x.value) for x in default_values],
|
||||
)
|
||||
generate_build_config_cmd.add(["--default-values-file", default_values_file])
|
||||
if values_file:
|
||||
generate_build_config_cmd.add(["--values-file", values_file])
|
||||
|
||||
build_config_dot_java = ctx.actions.declare_output(_get_output_name(java_package, "BuildConfig.java"))
|
||||
generate_build_config_cmd.add(["--output", build_config_dot_java.as_output()])
|
||||
|
||||
ctx.actions.run(
|
||||
generate_build_config_cmd,
|
||||
category = "android_generate_build_config",
|
||||
identifier = java_package,
|
||||
)
|
||||
|
||||
return build_config_dot_java
|
||||
|
||||
def _compile_and_package_build_config_dot_java(
|
||||
ctx: "context",
|
||||
java_package: str.type,
|
||||
build_config_dot_java: "artifact") -> "JavaCompileOutputs":
|
||||
return compile_to_jar(
|
||||
ctx,
|
||||
actions_prefix = "build_config_{}".format(java_package.replace(".", "_")),
|
||||
srcs = [build_config_dot_java],
|
||||
)
|
||||
|
||||
def get_build_config_fields(lines: [str.type]) -> ["BuildConfigField"]:
|
||||
return [_get_build_config_field(line) for line in lines]
|
||||
|
||||
def _get_build_config_field(line: str.type) -> "BuildConfigField":
|
||||
type_and_name, value = [x.strip() for x in line.split("=")]
|
||||
field_type, name = type_and_name.split()
|
||||
return BuildConfigField(type = field_type, name = name, value = value)
|
||||
|
||||
def _get_output_name(java_package: str.type, output_filename: str.type) -> str.type:
|
||||
return "android_build_config/{}/{}".format(java_package.replace(".", "_"), output_filename)
|
||||
89
vendor/cxx/tools/buck/prelude/android/android_instrumentation_apk.bzl
vendored
Normal file
89
vendor/cxx/tools/buck/prelude/android/android_instrumentation_apk.bzl
vendored
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load("@prelude//android:android_apk.bzl", "build_apk")
|
||||
load("@prelude//android:android_binary_native_library_rules.bzl", "get_android_binary_native_library_info")
|
||||
load("@prelude//android:android_binary_resources_rules.bzl", "get_android_binary_resources_info")
|
||||
load("@prelude//android:android_providers.bzl", "AndroidApkInfo", "AndroidApkUnderTestInfo", "AndroidInstrumentationApkInfo", "merge_android_packageable_info")
|
||||
load("@prelude//android:android_toolchain.bzl", "AndroidToolchainInfo")
|
||||
load("@prelude//android:configuration.bzl", "get_deps_by_platform")
|
||||
load("@prelude//android:dex_rules.bzl", "merge_to_single_dex")
|
||||
load("@prelude//java:java_providers.bzl", "create_java_packaging_dep", "get_all_java_packaging_deps")
|
||||
load("@prelude//utils:utils.bzl", "expect")
|
||||
|
||||
def android_instrumentation_apk_impl(ctx: "context"):
|
||||
# To begin with, let's just implement something that has a single DEX file and a manifest.
|
||||
_verify_params(ctx)
|
||||
|
||||
apk_under_test_info = ctx.attrs.apk[AndroidApkUnderTestInfo]
|
||||
|
||||
# android_instrumentation_apk should just use the same platforms and primary_platform as the APK-under-test
|
||||
unfiltered_deps_by_platform = get_deps_by_platform(ctx)
|
||||
for platform in apk_under_test_info.platforms:
|
||||
expect(
|
||||
platform in unfiltered_deps_by_platform,
|
||||
"Android instrumentation APK must have any platforms that are in the APK-under-test!",
|
||||
)
|
||||
deps_by_platform = {platform: deps for platform, deps in unfiltered_deps_by_platform.items() if platform in apk_under_test_info.platforms}
|
||||
primary_platform = apk_under_test_info.primary_platform
|
||||
deps = deps_by_platform[primary_platform]
|
||||
|
||||
java_packaging_deps = [packaging_dep for packaging_dep in get_all_java_packaging_deps(ctx, deps) if packaging_dep.dex and packaging_dep not in apk_under_test_info.java_packaging_deps]
|
||||
|
||||
android_packageable_info = merge_android_packageable_info(ctx.label, ctx.actions, deps)
|
||||
|
||||
resources_info = get_android_binary_resources_info(
|
||||
ctx,
|
||||
deps,
|
||||
android_packageable_info,
|
||||
java_packaging_deps = java_packaging_deps,
|
||||
use_proto_format = False,
|
||||
referenced_resources_lists = [],
|
||||
manifest_entries = apk_under_test_info.manifest_entries,
|
||||
resource_infos_to_exclude = apk_under_test_info.resource_infos,
|
||||
)
|
||||
android_toolchain = ctx.attrs._android_toolchain[AndroidToolchainInfo]
|
||||
java_packaging_deps += [
|
||||
create_java_packaging_dep(
|
||||
ctx,
|
||||
r_dot_java.library_output.full_library,
|
||||
dex_weight_factor = android_toolchain.r_dot_java_weight_factor,
|
||||
)
|
||||
for r_dot_java in resources_info.r_dot_javas
|
||||
]
|
||||
|
||||
# For instrumentation test APKs we always pre-dex, and we also always merge to a single dex.
|
||||
pre_dexed_libs = [java_packaging_dep.dex for java_packaging_dep in java_packaging_deps]
|
||||
dex_files_info = merge_to_single_dex(ctx, android_toolchain, pre_dexed_libs)
|
||||
|
||||
native_library_info = get_android_binary_native_library_info(
|
||||
ctx,
|
||||
android_packageable_info,
|
||||
deps_by_platform,
|
||||
prebuilt_native_library_dirs_to_exclude = apk_under_test_info.prebuilt_native_library_dirs,
|
||||
shared_libraries_to_exclude = apk_under_test_info.shared_libraries,
|
||||
)
|
||||
|
||||
output_apk = build_apk(
|
||||
label = ctx.label,
|
||||
actions = ctx.actions,
|
||||
android_toolchain = ctx.attrs._android_toolchain[AndroidToolchainInfo],
|
||||
keystore = apk_under_test_info.keystore,
|
||||
dex_files_info = dex_files_info,
|
||||
native_library_info = native_library_info,
|
||||
resources_info = resources_info,
|
||||
)
|
||||
|
||||
return [
|
||||
AndroidApkInfo(apk = output_apk, manifest = resources_info.manifest),
|
||||
AndroidInstrumentationApkInfo(apk_under_test = ctx.attrs.apk[AndroidApkInfo].apk),
|
||||
DefaultInfo(default_outputs = [output_apk]),
|
||||
]
|
||||
|
||||
def _verify_params(ctx: "context"):
|
||||
expect(ctx.attrs.aapt_mode == "aapt2", "aapt1 is deprecated!")
|
||||
expect(ctx.attrs.dex_tool == "d8", "dx is deprecated!")
|
||||
97
vendor/cxx/tools/buck/prelude/android/android_instrumentation_test.bzl
vendored
Normal file
97
vendor/cxx/tools/buck/prelude/android/android_instrumentation_test.bzl
vendored
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load("@prelude//android:android_providers.bzl", "AndroidApkInfo", "AndroidInstrumentationApkInfo")
|
||||
load("@prelude//android:android_toolchain.bzl", "AndroidToolchainInfo")
|
||||
load("@prelude//java:java_toolchain.bzl", "JavaToolchainInfo")
|
||||
load("@prelude//java/utils:java_utils.bzl", "get_path_separator")
|
||||
load("@prelude//utils:utils.bzl", "expect")
|
||||
load("@prelude//test/inject_test_run_info.bzl", "inject_test_run_info")
|
||||
|
||||
def android_instrumentation_test_impl(ctx: "context"):
|
||||
android_toolchain = ctx.attrs._android_toolchain[AndroidToolchainInfo]
|
||||
|
||||
cmd = [ctx.attrs._java_toolchain[JavaToolchainInfo].java_for_tests]
|
||||
|
||||
classpath = android_toolchain.instrumentation_test_runner_classpath
|
||||
|
||||
classpath_args = cmd_args()
|
||||
classpath_args.add("-classpath")
|
||||
classpath_args.add(cmd_args(classpath, delimiter = get_path_separator()))
|
||||
classpath_args_file = ctx.actions.write("classpath_args_file", classpath_args)
|
||||
cmd.append(cmd_args(classpath_args_file, format = "@{}").hidden(classpath_args))
|
||||
|
||||
cmd.append(android_toolchain.instrumentation_test_runner_main_class)
|
||||
|
||||
apk_info = ctx.attrs.apk.get(AndroidApkInfo)
|
||||
expect(apk_info != None, "Provided APK must have AndroidApkInfo!")
|
||||
|
||||
instrumentation_apk_info = ctx.attrs.apk.get(AndroidInstrumentationApkInfo)
|
||||
if instrumentation_apk_info != None:
|
||||
cmd.extend(["--apk-under-test-path", instrumentation_apk_info.apk_under_test])
|
||||
|
||||
target_package_file = ctx.actions.declare_output("target_package_file")
|
||||
package_file = ctx.actions.declare_output("package_file")
|
||||
test_runner_file = ctx.actions.declare_output("test_runner_file")
|
||||
manifest_utils_cmd = cmd_args(ctx.attrs._android_toolchain[AndroidToolchainInfo].manifest_utils[RunInfo])
|
||||
manifest_utils_cmd.add([
|
||||
"--manifest-path",
|
||||
apk_info.manifest,
|
||||
"--package-output",
|
||||
package_file.as_output(),
|
||||
"--target-package-output",
|
||||
target_package_file.as_output(),
|
||||
"--instrumentation-test-runner-output",
|
||||
test_runner_file.as_output(),
|
||||
])
|
||||
ctx.actions.run(manifest_utils_cmd, category = "get_manifest_info")
|
||||
|
||||
cmd.extend(
|
||||
[
|
||||
"--test-package-name",
|
||||
cmd_args(package_file, format = "@{}"),
|
||||
"--target-package-name",
|
||||
cmd_args(target_package_file, format = "@{}"),
|
||||
"--test-runner",
|
||||
cmd_args(test_runner_file, format = "@{}"),
|
||||
],
|
||||
)
|
||||
|
||||
cmd.extend(
|
||||
[
|
||||
"--adb-executable-path",
|
||||
"required_but_unused",
|
||||
"--instrumentation-apk-path",
|
||||
apk_info.apk,
|
||||
],
|
||||
)
|
||||
|
||||
test_info = ExternalRunnerTestInfo(
|
||||
type = "android_instrumentation",
|
||||
command = cmd,
|
||||
env = ctx.attrs.env,
|
||||
# TODO(T122022107) support static listing
|
||||
labels = ctx.attrs.labels + ["tpx::dynamic_listing_instrumentation_test"],
|
||||
contacts = ctx.attrs.contacts,
|
||||
run_from_project_root = True,
|
||||
use_project_relative_paths = True,
|
||||
executor_overrides = {
|
||||
"android-emulator": CommandExecutorConfig(
|
||||
local_enabled = False,
|
||||
remote_enabled = True,
|
||||
remote_execution_properties = {
|
||||
"platform": "android-emulator",
|
||||
"subplatform": "android-30",
|
||||
},
|
||||
remote_execution_use_case = "instrumentation-tests",
|
||||
),
|
||||
"static-listing": CommandExecutorConfig(local_enabled = True, remote_enabled = False),
|
||||
},
|
||||
)
|
||||
return inject_test_run_info(ctx, test_info) + [
|
||||
DefaultInfo(),
|
||||
]
|
||||
92
vendor/cxx/tools/buck/prelude/android/android_library.bzl
vendored
Normal file
92
vendor/cxx/tools/buck/prelude/android/android_library.bzl
vendored
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load(
|
||||
"@prelude//android:android_providers.bzl",
|
||||
"AndroidLibraryIntellijInfo",
|
||||
"AndroidResourceInfo",
|
||||
"merge_android_packageable_info",
|
||||
"merge_exported_android_resource_info",
|
||||
)
|
||||
load("@prelude//android:android_toolchain.bzl", "AndroidToolchainInfo")
|
||||
load("@prelude//android:r_dot_java.bzl", "get_dummy_r_dot_java")
|
||||
load("@prelude//java:java_library.bzl", "build_java_library")
|
||||
load("@prelude//java:java_providers.bzl", "create_native_providers", "to_list")
|
||||
load("@prelude//java:java_toolchain.bzl", "JavaToolchainInfo")
|
||||
load("@prelude//kotlin:kotlin_library.bzl", "build_kotlin_library")
|
||||
|
||||
def android_library_impl(ctx: "context") -> ["provider"]:
|
||||
packaging_deps = ctx.attrs.deps + (ctx.attrs.deps_query or []) + ctx.attrs.exported_deps + ctx.attrs.runtime_deps
|
||||
if ctx.attrs._build_only_native_code:
|
||||
shared_library_info, cxx_resource_info = create_native_providers(ctx.actions, ctx.label, packaging_deps)
|
||||
return [
|
||||
shared_library_info,
|
||||
cxx_resource_info,
|
||||
# Add an unused default output in case this target is used as an attr.source() anywhere.
|
||||
DefaultInfo(default_outputs = [ctx.actions.write("unused.jar", [])]),
|
||||
]
|
||||
|
||||
java_providers, android_library_intellij_info = build_android_library(ctx)
|
||||
android_providers = [android_library_intellij_info] if android_library_intellij_info else []
|
||||
|
||||
return to_list(java_providers) + [
|
||||
merge_android_packageable_info(
|
||||
ctx.label,
|
||||
ctx.actions,
|
||||
packaging_deps,
|
||||
manifest = ctx.attrs.manifest,
|
||||
),
|
||||
merge_exported_android_resource_info(ctx.attrs.exported_deps),
|
||||
] + android_providers
|
||||
|
||||
def build_android_library(
|
||||
ctx: "context") -> ("JavaProviders", [AndroidLibraryIntellijInfo.type, None]):
|
||||
java_toolchain = ctx.attrs._java_toolchain[JavaToolchainInfo]
|
||||
bootclasspath_entries = [] + ctx.attrs._android_toolchain[AndroidToolchainInfo].android_bootclasspath
|
||||
additional_classpath_entries = []
|
||||
android_library_intellij_info = None
|
||||
|
||||
dummy_r_dot_java = _get_dummy_r_dot_java(ctx, java_toolchain)
|
||||
if dummy_r_dot_java:
|
||||
additional_classpath_entries.append(dummy_r_dot_java)
|
||||
android_library_intellij_info = AndroidLibraryIntellijInfo(
|
||||
dummy_r_dot_java = dummy_r_dot_java,
|
||||
)
|
||||
|
||||
if ctx.attrs.language != None and ctx.attrs.language.lower() == "kotlin":
|
||||
return build_kotlin_library(
|
||||
ctx,
|
||||
additional_classpath_entries = additional_classpath_entries,
|
||||
bootclasspath_entries = bootclasspath_entries,
|
||||
), android_library_intellij_info
|
||||
else:
|
||||
return build_java_library(
|
||||
ctx,
|
||||
ctx.attrs.srcs,
|
||||
additional_classpath_entries = additional_classpath_entries,
|
||||
bootclasspath_entries = bootclasspath_entries,
|
||||
), android_library_intellij_info
|
||||
|
||||
def _get_dummy_r_dot_java(
|
||||
ctx: "context",
|
||||
java_toolchain: "JavaToolchainInfo") -> ["artifact", None]:
|
||||
android_resources = [resource for resource in filter(None, [
|
||||
x.get(AndroidResourceInfo)
|
||||
for x in ctx.attrs.deps + (ctx.attrs.deps_query or []) + ctx.attrs.provided_deps + (getattr(ctx.attrs, "provided_deps_query", []) or [])
|
||||
]) if resource.res != None]
|
||||
if len(android_resources) == 0:
|
||||
return None
|
||||
|
||||
dummy_r_dot_java_library_info = get_dummy_r_dot_java(
|
||||
ctx,
|
||||
ctx.attrs._android_toolchain[AndroidToolchainInfo].merge_android_resources[RunInfo],
|
||||
java_toolchain,
|
||||
dedupe(android_resources),
|
||||
ctx.attrs.resource_union_package,
|
||||
)
|
||||
|
||||
return dummy_r_dot_java_library_info.library_output.abi
|
||||
74
vendor/cxx/tools/buck/prelude/android/android_manifest.bzl
vendored
Normal file
74
vendor/cxx/tools/buck/prelude/android/android_manifest.bzl
vendored
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load("@prelude//android:android_providers.bzl", "AndroidManifestInfo", "merge_android_packageable_info")
|
||||
load("@prelude//android:android_toolchain.bzl", "AndroidToolchainInfo")
|
||||
|
||||
ROOT_APKMODULE_NAME = "dex"
|
||||
|
||||
def android_manifest_impl(ctx: "context") -> ["provider"]:
|
||||
output, merge_report = generate_android_manifest(
|
||||
ctx,
|
||||
ctx.attrs._android_toolchain[AndroidToolchainInfo].generate_manifest[RunInfo],
|
||||
ctx.attrs.skeleton,
|
||||
ROOT_APKMODULE_NAME,
|
||||
_get_manifests_from_deps(ctx),
|
||||
{},
|
||||
)
|
||||
|
||||
return [
|
||||
AndroidManifestInfo(manifest = output, merge_report = merge_report),
|
||||
DefaultInfo(default_outputs = [output], other_outputs = [merge_report]),
|
||||
]
|
||||
|
||||
def generate_android_manifest(
|
||||
ctx: "context",
|
||||
generate_manifest: RunInfo.type,
|
||||
manifest_skeleton: "artifact",
|
||||
module_name: str.type,
|
||||
manifests_tset: ["ManifestTSet", None],
|
||||
placeholder_entries: "dict") -> ("artifact", "artifact"):
|
||||
generate_manifest_cmd = cmd_args(generate_manifest)
|
||||
generate_manifest_cmd.add([
|
||||
"--skeleton-manifest",
|
||||
manifest_skeleton,
|
||||
"--module-name",
|
||||
module_name,
|
||||
])
|
||||
|
||||
manifests = manifests_tset.project_as_args("artifacts", ordering = "bfs") if manifests_tset else []
|
||||
library_manifest_paths_file = ctx.actions.write("library_manifest_paths_file", manifests)
|
||||
|
||||
generate_manifest_cmd.add(["--library-manifests-list", library_manifest_paths_file])
|
||||
generate_manifest_cmd.hidden(manifests)
|
||||
|
||||
placeholder_entries_args = cmd_args()
|
||||
for key, val in placeholder_entries.items():
|
||||
placeholder_entries_args.add(cmd_args(key, val, delimiter = " "))
|
||||
placeholder_entries_file = ctx.actions.write("placeholder_entries_file", placeholder_entries_args)
|
||||
|
||||
generate_manifest_cmd.add(["--placeholder-entries-list", placeholder_entries_file])
|
||||
|
||||
output = ctx.actions.declare_output("AndroidManifest.xml")
|
||||
merge_report = ctx.actions.declare_output("merge-report.txt")
|
||||
generate_manifest_cmd.add([
|
||||
"--output",
|
||||
output.as_output(),
|
||||
"--merge-report",
|
||||
merge_report.as_output(),
|
||||
])
|
||||
|
||||
ctx.actions.run(generate_manifest_cmd, category = "generate_manifest")
|
||||
|
||||
return (output, merge_report)
|
||||
|
||||
def _get_manifests_from_deps(ctx: "context") -> ["ManifestTSet", None]:
|
||||
if len(ctx.attrs.deps) == 0:
|
||||
return None
|
||||
|
||||
android_packageable_info = merge_android_packageable_info(ctx.label, ctx.actions, ctx.attrs.deps)
|
||||
return android_packageable_info.manifests
|
||||
108
vendor/cxx/tools/buck/prelude/android/android_prebuilt_aar.bzl
vendored
Normal file
108
vendor/cxx/tools/buck/prelude/android/android_prebuilt_aar.bzl
vendored
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load("@prelude//android:android_providers.bzl", "AndroidResourceInfo", "PrebuiltNativeLibraryDir", "merge_android_packageable_info")
|
||||
load("@prelude//android:android_resource.bzl", "aapt2_compile", "extract_package_from_manifest")
|
||||
load("@prelude//android:android_toolchain.bzl", "AndroidToolchainInfo")
|
||||
load(
|
||||
"@prelude//java:java_providers.bzl",
|
||||
"JavaClasspathEntry",
|
||||
"create_abi",
|
||||
"create_java_library_providers",
|
||||
)
|
||||
load("@prelude//java:java_toolchain.bzl", "JavaToolchainInfo")
|
||||
|
||||
def android_prebuilt_aar_impl(ctx: "context") -> ["provider"]:
|
||||
manifest = ctx.actions.declare_output("AndroidManifest.xml")
|
||||
all_classes_jar = ctx.actions.declare_output("classes.jar")
|
||||
r_dot_txt = ctx.actions.declare_output("R.txt")
|
||||
res = ctx.actions.declare_output("res")
|
||||
assets = ctx.actions.declare_output("assets")
|
||||
jni = ctx.actions.declare_output("jni")
|
||||
annotation_jars_dir = ctx.actions.declare_output("annotation_jars")
|
||||
|
||||
android_toolchain = ctx.attrs._android_toolchain[AndroidToolchainInfo]
|
||||
unpack_aar_tool = android_toolchain.unpack_aar[RunInfo]
|
||||
java_toolchain = ctx.attrs._java_toolchain[JavaToolchainInfo]
|
||||
jar_tool = java_toolchain.jar
|
||||
|
||||
unpack_aar_cmd = [
|
||||
unpack_aar_tool,
|
||||
"--aar",
|
||||
ctx.attrs.aar,
|
||||
"--manifest-path",
|
||||
manifest.as_output(),
|
||||
"--all-classes-jar-path",
|
||||
all_classes_jar.as_output(),
|
||||
"--r-dot-txt-path",
|
||||
r_dot_txt.as_output(),
|
||||
"--res-path",
|
||||
res.as_output(),
|
||||
"--assets-path",
|
||||
assets.as_output(),
|
||||
"--jni-path",
|
||||
jni.as_output(),
|
||||
"--annotation-jars-dir",
|
||||
annotation_jars_dir.as_output(),
|
||||
"--jar-tool",
|
||||
jar_tool,
|
||||
]
|
||||
|
||||
ctx.actions.run(unpack_aar_cmd, category = "android_unpack_aar")
|
||||
|
||||
resource_info = AndroidResourceInfo(
|
||||
aapt2_compile_output = aapt2_compile(ctx, res, android_toolchain),
|
||||
allow_strings_as_assets_resource_filtering = True,
|
||||
assets = assets,
|
||||
manifest_file = manifest,
|
||||
r_dot_java_package = extract_package_from_manifest(ctx, manifest),
|
||||
res = res,
|
||||
text_symbols = r_dot_txt,
|
||||
)
|
||||
|
||||
abi = None if java_toolchain.is_bootstrap_toolchain else create_abi(ctx.actions, java_toolchain.class_abi_generator, all_classes_jar)
|
||||
|
||||
library_output_classpath_entry = JavaClasspathEntry(
|
||||
full_library = all_classes_jar,
|
||||
abi = abi or all_classes_jar,
|
||||
required_for_source_only_abi = ctx.attrs.required_for_source_only_abi,
|
||||
)
|
||||
|
||||
java_library_info, java_packaging_info, shared_library_info, cxx_resource_info, template_placeholder_info, java_library_intellij_info = create_java_library_providers(
|
||||
ctx = ctx,
|
||||
library_output = library_output_classpath_entry,
|
||||
exported_deps = ctx.attrs.deps,
|
||||
needs_desugar = True,
|
||||
is_prebuilt_jar = True,
|
||||
annotation_jars_dir = annotation_jars_dir,
|
||||
)
|
||||
|
||||
native_library = PrebuiltNativeLibraryDir(
|
||||
raw_target = ctx.label.raw_target(),
|
||||
dir = jni,
|
||||
for_primary_apk = ctx.attrs.use_system_library_loader,
|
||||
is_asset = False,
|
||||
)
|
||||
|
||||
return [
|
||||
java_library_info,
|
||||
java_packaging_info,
|
||||
shared_library_info,
|
||||
cxx_resource_info,
|
||||
template_placeholder_info,
|
||||
java_library_intellij_info,
|
||||
merge_android_packageable_info(ctx.label, ctx.actions, ctx.attrs.deps, manifest = manifest, prebuilt_native_library_dir = native_library, resource_info = resource_info),
|
||||
resource_info,
|
||||
DefaultInfo(default_outputs = [all_classes_jar], other_outputs = [
|
||||
manifest,
|
||||
r_dot_txt,
|
||||
res,
|
||||
assets,
|
||||
jni,
|
||||
annotation_jars_dir,
|
||||
]),
|
||||
]
|
||||
283
vendor/cxx/tools/buck/prelude/android/android_providers.bzl
vendored
Normal file
283
vendor/cxx/tools/buck/prelude/android/android_providers.bzl
vendored
Normal file
|
|
@ -0,0 +1,283 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
Aapt2LinkInfo = record(
|
||||
# "APK" containing resources to be used by the Android binary
|
||||
primary_resources_apk = "artifact",
|
||||
# proguard config needed to retain used resources
|
||||
proguard_config_file = "artifact",
|
||||
# R.txt containing all the linked resources
|
||||
r_dot_txt = "artifact",
|
||||
)
|
||||
|
||||
AndroidBinaryNativeLibsInfo = record(
|
||||
apk_under_test_prebuilt_native_library_dirs = ["PrebuiltNativeLibraryDir"],
|
||||
apk_under_test_shared_libraries = ["SharedLibrary"],
|
||||
exopackage_info = ["ExopackageNativeInfo", None],
|
||||
native_lib_assets = ["artifact"],
|
||||
native_libs_for_primary_apk = ["artifact"],
|
||||
unstripped_libs = ["artifact"],
|
||||
)
|
||||
|
||||
AndroidBinaryResourcesInfo = record(
|
||||
# Optional information about resources that should be exopackaged
|
||||
exopackage_info = ["ExopackageResourcesInfo", None],
|
||||
# manifest to be used by the APK
|
||||
manifest = "artifact",
|
||||
# zip containing any strings packaged as assets
|
||||
packaged_string_assets = ["artifact", None],
|
||||
# "APK" containing resources to be used by the Android binary
|
||||
primary_resources_apk = "artifact",
|
||||
# proguard config needed to retain used resources
|
||||
proguard_config_file = "artifact",
|
||||
# R.java jars containing all the linked resources
|
||||
r_dot_javas = ["JavaLibraryInfo"],
|
||||
# directory containing filtered string resources files
|
||||
string_source_map = ["artifact", None],
|
||||
# list of jars that could contain resources that should be packaged into the APK
|
||||
jar_files_that_may_contain_resources = ["artifact"],
|
||||
# The resource infos that are used in this APK
|
||||
unfiltered_resource_infos = ["AndroidResourceInfo"],
|
||||
)
|
||||
|
||||
# Information about an `android_build_config`
|
||||
BuildConfigField = record(
|
||||
type = str.type,
|
||||
name = str.type,
|
||||
value = str.type,
|
||||
)
|
||||
|
||||
AndroidBuildConfigInfo = provider(
|
||||
fields = [
|
||||
"package", # str.type
|
||||
"build_config_fields", # ["BuildConfigField"]
|
||||
],
|
||||
)
|
||||
|
||||
# Information about an `android_manifest`
|
||||
AndroidManifestInfo = provider(
|
||||
fields = [
|
||||
"manifest", # artifact
|
||||
"merge_report", # artifact
|
||||
],
|
||||
)
|
||||
|
||||
AndroidApkInfo = provider(
|
||||
fields = [
|
||||
"apk",
|
||||
"manifest",
|
||||
],
|
||||
)
|
||||
|
||||
AndroidApkUnderTestInfo = provider(
|
||||
fields = [
|
||||
"java_packaging_deps", # ["JavaPackagingDep"]
|
||||
"keystore", # "KeystoreInfo"
|
||||
"manifest_entries", # dict.type
|
||||
"prebuilt_native_library_dirs", # ["PrebuiltNativeLibraryDir"]
|
||||
"platforms", # [str.type]
|
||||
"primary_platform", # str.type
|
||||
"resource_infos", # ["ResourceInfos"]
|
||||
"shared_libraries", # ["SharedLibrary"]
|
||||
],
|
||||
)
|
||||
|
||||
AndroidInstrumentationApkInfo = provider(
|
||||
fields = [
|
||||
"apk_under_test", # "artifact"
|
||||
],
|
||||
)
|
||||
|
||||
CPU_FILTER_TO_ABI_DIRECTORY = {
|
||||
"arm64": "arm64-v8a",
|
||||
"armv7": "armeabi-v7a",
|
||||
"x86": "x86",
|
||||
"x86_64": "x86_64",
|
||||
}
|
||||
|
||||
PrebuiltNativeLibraryDir = record(
|
||||
raw_target = "target_label",
|
||||
dir = "artifact", # contains subdirectories for different ABIs.
|
||||
for_primary_apk = bool.type,
|
||||
is_asset = bool.type,
|
||||
)
|
||||
|
||||
def _artifacts(value: "artifact"):
|
||||
return value
|
||||
|
||||
AndroidBuildConfigInfoTSet = transitive_set()
|
||||
AndroidDepsTSet = transitive_set()
|
||||
ManifestTSet = transitive_set(args_projections = {"artifacts": _artifacts})
|
||||
PrebuiltNativeLibraryDirTSet = transitive_set()
|
||||
ResourceInfoTSet = transitive_set()
|
||||
|
||||
DepsInfo = record(
|
||||
name = "target_label",
|
||||
deps = ["target_label"],
|
||||
)
|
||||
|
||||
AndroidPackageableInfo = provider(
|
||||
fields = [
|
||||
"target_label", # "target_label"
|
||||
"build_config_infos", # ["AndroidBuildConfigInfoTSet", None]
|
||||
"deps", # ["AndroidDepsTSet", None]
|
||||
"manifests", # ["ManifestTSet", None]
|
||||
"prebuilt_native_library_dirs", # ["PrebuiltNativeLibraryDirTSet", None]
|
||||
"resource_infos", # ["AndroidResourceInfoTSet", None]
|
||||
],
|
||||
)
|
||||
|
||||
# Information about an `android_resource`
|
||||
AndroidResourceInfo = provider(
|
||||
fields = [
|
||||
# output of running `aapt2_compile` on the resources, if resources are present
|
||||
"aapt2_compile_output", # ["artifact", None]
|
||||
# if False, then the "res" are not affected by the strings-as-assets resource filter
|
||||
"allow_strings_as_assets_resource_filtering", # bool.type
|
||||
# assets defined by this rule. May be empty
|
||||
"assets", # ["artifact", None]
|
||||
# manifest file used by the resources, if resources are present
|
||||
"manifest_file", # ["artifact", None]
|
||||
# package used for R.java, if resources are present
|
||||
"r_dot_java_package", # ["artifact", None]
|
||||
# resources defined by this rule. May be empty
|
||||
"res", # ["artifact", None]
|
||||
# symbols defined by the resources, if resources are present
|
||||
"text_symbols", # ["artifact", None]
|
||||
],
|
||||
)
|
||||
|
||||
# `AndroidResourceInfos` that are exposed via `exported_deps`
|
||||
ExportedAndroidResourceInfo = provider(
|
||||
fields = [
|
||||
"resource_infos", # ["AndroidResourceInfo"]
|
||||
],
|
||||
)
|
||||
|
||||
ExopackageDexInfo = record(
|
||||
metadata = "artifact",
|
||||
directory = "artifact",
|
||||
)
|
||||
|
||||
ExopackageNativeInfo = record(
|
||||
metadata = "artifact",
|
||||
directory = "artifact",
|
||||
)
|
||||
|
||||
ExopackageResourcesInfo = record(
|
||||
assets = ["artifact", None],
|
||||
assets_hash = ["artifact", None],
|
||||
res = "artifact",
|
||||
res_hash = "artifact",
|
||||
third_party_jar_resources = "artifact",
|
||||
third_party_jar_resources_hash = "artifact",
|
||||
)
|
||||
|
||||
DexFilesInfo = record(
|
||||
primary_dex = "artifact",
|
||||
primary_dex_class_names = ["artifact", None],
|
||||
secondary_dex_dirs = ["artifact"],
|
||||
secondary_dex_exopackage_info = [ExopackageDexInfo.type, None],
|
||||
proguard_text_files_path = ["artifact", None],
|
||||
)
|
||||
|
||||
ExopackageInfo = record(
|
||||
secondary_dex_info = [ExopackageDexInfo.type, None],
|
||||
native_library_info = [ExopackageNativeInfo.type, None],
|
||||
resources_info = [ExopackageResourcesInfo.type, None],
|
||||
)
|
||||
|
||||
AndroidLibraryIntellijInfo = provider(
|
||||
"Information about android library that is required for Intellij project generation",
|
||||
fields = [
|
||||
"dummy_r_dot_java", # ["artifact", None]
|
||||
],
|
||||
)
|
||||
|
||||
def merge_android_packageable_info(
|
||||
label: "label",
|
||||
actions: "actions",
|
||||
deps: ["dependency"],
|
||||
build_config_info: ["AndroidBuildConfigInfo", None] = None,
|
||||
manifest: ["artifact", None] = None,
|
||||
prebuilt_native_library_dir: [PrebuiltNativeLibraryDir.type, None] = None,
|
||||
resource_info: ["AndroidResourceInfo", None] = None) -> "AndroidPackageableInfo":
|
||||
android_packageable_deps = filter(None, [x.get(AndroidPackageableInfo) for x in deps])
|
||||
|
||||
build_config_infos = _get_transitive_set(
|
||||
actions,
|
||||
filter(None, [dep.build_config_infos for dep in android_packageable_deps]),
|
||||
build_config_info,
|
||||
AndroidBuildConfigInfoTSet,
|
||||
)
|
||||
|
||||
deps = _get_transitive_set(
|
||||
actions,
|
||||
filter(None, [dep.deps for dep in android_packageable_deps]),
|
||||
DepsInfo(
|
||||
name = label.raw_target(),
|
||||
deps = [dep.target_label for dep in android_packageable_deps],
|
||||
),
|
||||
AndroidDepsTSet,
|
||||
)
|
||||
|
||||
manifests = _get_transitive_set(
|
||||
actions,
|
||||
filter(None, [dep.manifests for dep in android_packageable_deps]),
|
||||
manifest,
|
||||
ManifestTSet,
|
||||
)
|
||||
|
||||
prebuilt_native_library_dirs = _get_transitive_set(
|
||||
actions,
|
||||
filter(None, [dep.prebuilt_native_library_dirs for dep in android_packageable_deps]),
|
||||
prebuilt_native_library_dir,
|
||||
PrebuiltNativeLibraryDirTSet,
|
||||
)
|
||||
|
||||
resource_infos = _get_transitive_set(
|
||||
actions,
|
||||
filter(None, [dep.resource_infos for dep in android_packageable_deps]),
|
||||
resource_info,
|
||||
ResourceInfoTSet,
|
||||
)
|
||||
|
||||
return AndroidPackageableInfo(
|
||||
target_label = label.raw_target(),
|
||||
build_config_infos = build_config_infos,
|
||||
deps = deps,
|
||||
manifests = manifests,
|
||||
prebuilt_native_library_dirs = prebuilt_native_library_dirs,
|
||||
resource_infos = resource_infos,
|
||||
)
|
||||
|
||||
def _get_transitive_set(
|
||||
actions: "actions",
|
||||
children: ["transitive_set"],
|
||||
node: "_a",
|
||||
transitive_set_definition: "transitive_set_definition") -> ["transitive_set", None]:
|
||||
kwargs = {}
|
||||
if children:
|
||||
kwargs["children"] = children
|
||||
if node:
|
||||
kwargs["value"] = node
|
||||
|
||||
return actions.tset(transitive_set_definition, **kwargs) if kwargs else None
|
||||
|
||||
def merge_exported_android_resource_info(
|
||||
exported_deps: ["dependency"]) -> "ExportedAndroidResourceInfo":
|
||||
exported_android_resource_infos = []
|
||||
for exported_dep in exported_deps:
|
||||
exported_resource_info = exported_dep.get(ExportedAndroidResourceInfo)
|
||||
if exported_resource_info:
|
||||
exported_android_resource_infos += exported_resource_info.resource_infos
|
||||
|
||||
android_resource = exported_dep.get(AndroidResourceInfo)
|
||||
if android_resource:
|
||||
exported_android_resource_infos.append(android_resource)
|
||||
|
||||
return ExportedAndroidResourceInfo(resource_infos = dedupe(exported_android_resource_infos))
|
||||
143
vendor/cxx/tools/buck/prelude/android/android_resource.bzl
vendored
Normal file
143
vendor/cxx/tools/buck/prelude/android/android_resource.bzl
vendored
Normal file
|
|
@ -0,0 +1,143 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load("@prelude//java:java_providers.bzl", "get_java_packaging_info")
|
||||
load("@prelude//utils:utils.bzl", "expect")
|
||||
load(":android_providers.bzl", "AndroidResourceInfo", "ExportedAndroidResourceInfo", "merge_android_packageable_info")
|
||||
load(":android_toolchain.bzl", "AndroidToolchainInfo")
|
||||
|
||||
JAVA_PACKAGE_FILENAME = "java_package.txt"
|
||||
|
||||
def _convert_to_artifact_dir(ctx: "context", attr: ["dependency", "dict", "artifact", None], attr_name: str.type) -> ["artifact", None]:
|
||||
if type(attr) == "dependency":
|
||||
expect(len(attr[DefaultInfo].default_outputs) == 1, "Expect one default output from build dep of attr {}!".format(attr_name))
|
||||
return attr[DefaultInfo].default_outputs[0]
|
||||
elif type(attr) == "dict" and len(attr) > 0:
|
||||
return ctx.actions.symlinked_dir("{}_dir".format(attr_name), attr)
|
||||
else:
|
||||
return attr
|
||||
|
||||
def android_resource_impl(ctx: "context") -> ["provider"]:
|
||||
if ctx.attrs._build_only_native_code:
|
||||
return [DefaultInfo()]
|
||||
|
||||
# TODO(T100007184) filter res/assets by ignored filenames
|
||||
sub_targets = {}
|
||||
providers = []
|
||||
default_outputs = []
|
||||
|
||||
res = _convert_to_artifact_dir(ctx, ctx.attrs.res, "res")
|
||||
assets = _convert_to_artifact_dir(ctx, ctx.attrs.assets, "assets")
|
||||
|
||||
if res:
|
||||
aapt2_compile_output = aapt2_compile(ctx, res, ctx.attrs._android_toolchain[AndroidToolchainInfo])
|
||||
|
||||
sub_targets["aapt2_compile"] = [DefaultInfo(default_outputs = [aapt2_compile_output])]
|
||||
|
||||
r_dot_txt_output = get_text_symbols(ctx, res, ctx.attrs.deps)
|
||||
default_outputs.append(r_dot_txt_output)
|
||||
|
||||
r_dot_java_package = _get_package(ctx, ctx.attrs.package, ctx.attrs.manifest)
|
||||
resource_info = AndroidResourceInfo(
|
||||
aapt2_compile_output = aapt2_compile_output,
|
||||
allow_strings_as_assets_resource_filtering = not ctx.attrs.has_whitelisted_strings,
|
||||
assets = assets,
|
||||
manifest_file = ctx.attrs.manifest,
|
||||
r_dot_java_package = r_dot_java_package,
|
||||
res = res,
|
||||
text_symbols = r_dot_txt_output,
|
||||
)
|
||||
else:
|
||||
resource_info = AndroidResourceInfo(
|
||||
aapt2_compile_output = None,
|
||||
allow_strings_as_assets_resource_filtering = not ctx.attrs.has_whitelisted_strings,
|
||||
assets = assets,
|
||||
manifest_file = ctx.attrs.manifest,
|
||||
r_dot_java_package = None,
|
||||
res = None,
|
||||
text_symbols = None,
|
||||
)
|
||||
providers.append(resource_info)
|
||||
providers.append(merge_android_packageable_info(ctx.label, ctx.actions, ctx.attrs.deps, manifest = ctx.attrs.manifest, resource_info = resource_info))
|
||||
providers.append(get_java_packaging_info(ctx, ctx.attrs.deps))
|
||||
providers.append(DefaultInfo(default_outputs = default_outputs, sub_targets = sub_targets))
|
||||
|
||||
return providers
|
||||
|
||||
def aapt2_compile(
|
||||
ctx: "context",
|
||||
resources_dir: "artifact",
|
||||
android_toolchain: "AndroidToolchainInfo",
|
||||
skip_crunch_pngs: bool.type = False,
|
||||
identifier: [str.type, None] = None) -> "artifact":
|
||||
aapt2_command = cmd_args(android_toolchain.aapt2)
|
||||
aapt2_command.add("compile")
|
||||
aapt2_command.add("--legacy")
|
||||
if skip_crunch_pngs:
|
||||
aapt2_command.add("--no-crunch")
|
||||
aapt2_command.add(["--dir", resources_dir])
|
||||
aapt2_output = ctx.actions.declare_output("{}_resources.flata".format(identifier) if identifier else "resources.flata")
|
||||
aapt2_command.add("-o", aapt2_output.as_output())
|
||||
|
||||
ctx.actions.run(aapt2_command, category = "aapt2_compile", identifier = identifier)
|
||||
|
||||
return aapt2_output
|
||||
|
||||
def _get_package(ctx: "context", package: [str.type, None], manifest: ["artifact", None]) -> "artifact":
|
||||
if package:
|
||||
return ctx.actions.write(JAVA_PACKAGE_FILENAME, package)
|
||||
else:
|
||||
expect(manifest != None, "if package is not declared then a manifest must be")
|
||||
return extract_package_from_manifest(ctx, manifest)
|
||||
|
||||
def extract_package_from_manifest(ctx: "context", manifest: "artifact") -> "artifact":
|
||||
r_dot_java_package = ctx.actions.declare_output(JAVA_PACKAGE_FILENAME)
|
||||
extract_package_cmd = cmd_args(ctx.attrs._android_toolchain[AndroidToolchainInfo].manifest_utils[RunInfo])
|
||||
extract_package_cmd.add(["--manifest-path", manifest])
|
||||
extract_package_cmd.add(["--package-output", r_dot_java_package.as_output()])
|
||||
|
||||
ctx.actions.run(extract_package_cmd, category = "android_extract_package")
|
||||
|
||||
return r_dot_java_package
|
||||
|
||||
def get_text_symbols(
|
||||
ctx: "context",
|
||||
res: "artifact",
|
||||
deps: ["dependency"],
|
||||
identifier: [str.type, None] = None):
|
||||
mini_aapt_cmd = cmd_args(ctx.attrs._android_toolchain[AndroidToolchainInfo].mini_aapt[RunInfo])
|
||||
|
||||
mini_aapt_cmd.add(["--resource-paths", res])
|
||||
|
||||
dep_symbol_paths = cmd_args()
|
||||
dep_symbols = _get_dep_symbols(deps)
|
||||
dep_symbol_paths.add(dep_symbols)
|
||||
|
||||
dep_symbol_paths_file, _ = ctx.actions.write("{}_dep_symbol_paths_file".format(identifier) if identifier else "dep_symbol_paths_file", dep_symbol_paths, allow_args = True)
|
||||
|
||||
mini_aapt_cmd.add(["--dep-symbol-paths", dep_symbol_paths_file])
|
||||
mini_aapt_cmd.hidden(dep_symbols)
|
||||
|
||||
text_symbols = ctx.actions.declare_output("{}_R.txt".format(identifier) if identifier else "R.txt")
|
||||
mini_aapt_cmd.add(["--output-path", text_symbols.as_output()])
|
||||
|
||||
ctx.actions.run(mini_aapt_cmd, category = "mini_aapt", identifier = identifier)
|
||||
|
||||
return text_symbols
|
||||
|
||||
def _get_dep_symbols(deps: ["dependency"]) -> ["artifact"]:
|
||||
dep_symbols = []
|
||||
for dep in deps:
|
||||
android_resource_info = dep.get(AndroidResourceInfo)
|
||||
exported_android_resource_info = dep.get(ExportedAndroidResourceInfo)
|
||||
expect(android_resource_info != None or exported_android_resource_info != None, "Dependencies of `android_resource` rules should be `android_resource`s or `android_library`s")
|
||||
if android_resource_info and android_resource_info.text_symbols:
|
||||
dep_symbols.append(android_resource_info.text_symbols)
|
||||
if exported_android_resource_info:
|
||||
dep_symbols += [resource_info.text_symbols for resource_info in exported_android_resource_info.resource_infos if resource_info.text_symbols]
|
||||
|
||||
return dedupe(dep_symbols)
|
||||
50
vendor/cxx/tools/buck/prelude/android/android_toolchain.bzl
vendored
Normal file
50
vendor/cxx/tools/buck/prelude/android/android_toolchain.bzl
vendored
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
AndroidPlatformInfo = provider(fields = [
|
||||
"name",
|
||||
])
|
||||
|
||||
AndroidToolchainInfo = provider(fields = [
|
||||
"aapt2",
|
||||
"adb",
|
||||
"aidl",
|
||||
"android_jar",
|
||||
"android_bootclasspath",
|
||||
"apk_builder",
|
||||
"apk_module_graph",
|
||||
"combine_native_library_dirs",
|
||||
"compress_libraries",
|
||||
"d8_command",
|
||||
"exo_resources_rewriter",
|
||||
"exopackage_agent_apk",
|
||||
"filter_dex_class_names",
|
||||
"filter_prebuilt_native_library_dir",
|
||||
"multi_dex_command",
|
||||
"copy_string_resources",
|
||||
"filter_resources",
|
||||
"framework_aidl_file",
|
||||
"generate_build_config",
|
||||
"generate_manifest",
|
||||
"instrumentation_test_runner_classpath",
|
||||
"instrumentation_test_runner_main_class",
|
||||
"manifest_utils",
|
||||
"merge_android_resources",
|
||||
"merge_assets",
|
||||
"merge_third_party_jar_resources",
|
||||
"mini_aapt",
|
||||
"native_libs_as_assets_metadata",
|
||||
"optimized_proguard_config",
|
||||
"package_strings_as_assets",
|
||||
"proguard_config",
|
||||
"proguard_jar",
|
||||
"proguard_max_heap_size",
|
||||
"r_dot_java_weight_factor",
|
||||
"secondary_dex_weight_limit",
|
||||
"unpack_aar",
|
||||
"zipalign",
|
||||
])
|
||||
35
vendor/cxx/tools/buck/prelude/android/apk_genrule.bzl
vendored
Normal file
35
vendor/cxx/tools/buck/prelude/android/apk_genrule.bzl
vendored
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load("@prelude//:genrule.bzl", "process_genrule")
|
||||
load("@prelude//android:android_providers.bzl", "AndroidApkInfo", "AndroidApkUnderTestInfo")
|
||||
load("@prelude//utils:utils.bzl", "expect")
|
||||
|
||||
def apk_genrule_impl(ctx: "context") -> ["provider"]:
|
||||
# TODO(T104150125) The underlying APK should not have exopackage enabled
|
||||
input_android_apk_info = ctx.attrs.apk[AndroidApkInfo]
|
||||
expect(input_android_apk_info != None, "'apk' attribute must be an Android APK!")
|
||||
input_android_apk_under_test_info = ctx.attrs.apk[AndroidApkUnderTestInfo]
|
||||
|
||||
env_vars = {
|
||||
"APK": cmd_args(input_android_apk_info.apk),
|
||||
}
|
||||
|
||||
# Like buck1, we ignore the 'out' attribute and construct the output path ourselves.
|
||||
output_apk_name = "{}.apk".format(ctx.label.name)
|
||||
|
||||
genrule_providers = process_genrule(ctx, output_apk_name, None, env_vars)
|
||||
|
||||
expect(len(genrule_providers) == 1 and type(genrule_providers[0]) == DefaultInfo.type, "Expecting just a single DefaultInfo, but got {}".format(genrule_providers))
|
||||
output_apk = genrule_providers[0].default_outputs[0]
|
||||
|
||||
return genrule_providers + [
|
||||
AndroidApkInfo(
|
||||
apk = output_apk,
|
||||
manifest = input_android_apk_info.manifest,
|
||||
),
|
||||
] + filter(None, [input_android_apk_under_test_info])
|
||||
190
vendor/cxx/tools/buck/prelude/android/configuration.bzl
vendored
Normal file
190
vendor/cxx/tools/buck/prelude/android/configuration.bzl
vendored
Normal file
|
|
@ -0,0 +1,190 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load("@prelude//android:android_providers.bzl", "CPU_FILTER_TO_ABI_DIRECTORY")
|
||||
load("@prelude//android:min_sdk_version.bzl", "get_min_sdk_version_constraint_value_name", "get_min_sdk_version_range")
|
||||
|
||||
# FIXME: prelude// should be standalone (not refer to ovr_config//)
|
||||
_REFS = {
|
||||
"arm64": "ovr_config//cpu/constraints:arm64",
|
||||
"armv7": "ovr_config//cpu/constraints:arm32",
|
||||
"build_only_native_code": "fbsource//xplat/buck2/platform/android:build_only_native_code",
|
||||
"building_android_binary": "prelude//os:building_android_binary",
|
||||
"cpu": "ovr_config//cpu/constraints:cpu",
|
||||
"do_not_build_only_native_code": "fbsource//xplat/buck2/platform/android:do_not_build_only_native_code",
|
||||
"maybe_build_only_native_code": "fbsource//xplat/buck2/platform/android:maybe_build_only_native_code",
|
||||
"maybe_building_android_binary": "prelude//os:maybe_building_android_binary",
|
||||
"min_sdk_version": "fbsource//xplat/buck2/platform/android:min_sdk_version",
|
||||
"x86": "ovr_config//cpu/constraints:x86_32",
|
||||
"x86_64": "ovr_config//cpu/constraints:x86_64",
|
||||
}
|
||||
for min_sdk in get_min_sdk_version_range():
|
||||
constraint_value_name = get_min_sdk_version_constraint_value_name(min_sdk)
|
||||
_REFS[constraint_value_name] = "fbsource//xplat/buck2/platform/android:{}".format(constraint_value_name)
|
||||
|
||||
def _cpu_split_transition_instrumentation_test_apk_impl(
|
||||
platform: PlatformInfo.type,
|
||||
refs: struct.type,
|
||||
attrs: struct.type) -> {str.type: PlatformInfo.type}:
|
||||
cpu_filters = attrs.cpu_filters or CPU_FILTER_TO_ABI_DIRECTORY.keys()
|
||||
|
||||
return _cpu_split_transition(platform, refs, cpu_filters, attrs.min_sdk_version, build_only_native_code_on_secondary_platforms = False)
|
||||
|
||||
def _cpu_split_transition_impl(
|
||||
platform: PlatformInfo.type,
|
||||
refs: struct.type,
|
||||
attrs: struct.type) -> {str.type: PlatformInfo.type}:
|
||||
cpu_filters = attrs.cpu_filters or CPU_FILTER_TO_ABI_DIRECTORY.keys()
|
||||
do_not_build_only_native_code = refs.do_not_build_only_native_code[ConstraintValueInfo].label in [constraint.label for constraint in platform.configuration.constraints.values()]
|
||||
|
||||
return _cpu_split_transition(platform, refs, cpu_filters, attrs.min_sdk_version, build_only_native_code_on_secondary_platforms = not do_not_build_only_native_code)
|
||||
|
||||
def _cpu_split_transition(
|
||||
platform: PlatformInfo.type,
|
||||
refs: struct.type,
|
||||
cpu_filters: [str.type],
|
||||
min_sdk_version: [int.type, None],
|
||||
build_only_native_code_on_secondary_platforms: bool.type) -> {str.type: PlatformInfo.type}:
|
||||
cpu = refs.cpu
|
||||
x86 = refs.x86[ConstraintValueInfo]
|
||||
x86_64 = refs.x86_64[ConstraintValueInfo]
|
||||
armv7 = refs.armv7[ConstraintValueInfo]
|
||||
arm64 = refs.arm64[ConstraintValueInfo]
|
||||
|
||||
cpu_name_to_cpu_constraint = {}
|
||||
for cpu_filter in cpu_filters:
|
||||
if cpu_filter == "x86":
|
||||
cpu_name_to_cpu_constraint["x86"] = x86
|
||||
elif cpu_filter == "armv7":
|
||||
cpu_name_to_cpu_constraint["armv7"] = armv7
|
||||
elif cpu_filter == "x86_64":
|
||||
cpu_name_to_cpu_constraint["x86_64"] = x86_64
|
||||
elif cpu_filter == "arm64":
|
||||
cpu_name_to_cpu_constraint["arm64"] = arm64
|
||||
else:
|
||||
fail("Unexpected cpu_filter: {}".format(cpu_filter))
|
||||
|
||||
base_constraints = {
|
||||
constraint_setting_label: constraint_setting_value
|
||||
for (constraint_setting_label, constraint_setting_value) in platform.configuration.constraints.items()
|
||||
if constraint_setting_label != cpu[ConstraintSettingInfo].label and constraint_setting_label != refs.maybe_build_only_native_code[ConstraintSettingInfo].label
|
||||
}
|
||||
|
||||
base_constraints[refs.maybe_building_android_binary[ConstraintSettingInfo].label] = refs.building_android_binary[ConstraintValueInfo]
|
||||
|
||||
if min_sdk_version:
|
||||
base_constraints[refs.min_sdk_version[ConstraintSettingInfo].label] = _get_min_sdk_constraint_value(min_sdk_version, refs)
|
||||
|
||||
new_configs = {}
|
||||
for platform_name, cpu_constraint in cpu_name_to_cpu_constraint.items():
|
||||
updated_constraints = dict(base_constraints)
|
||||
updated_constraints[refs.cpu[ConstraintSettingInfo].label] = cpu_constraint
|
||||
if len(new_configs) > 0 and build_only_native_code_on_secondary_platforms:
|
||||
updated_constraints[refs.maybe_build_only_native_code[ConstraintSettingInfo].label] = refs.build_only_native_code[ConstraintValueInfo]
|
||||
|
||||
new_configs[platform_name] = PlatformInfo(
|
||||
label = platform_name,
|
||||
configuration = ConfigurationInfo(
|
||||
constraints = updated_constraints,
|
||||
values = platform.configuration.values,
|
||||
),
|
||||
)
|
||||
|
||||
return new_configs
|
||||
|
||||
def _cpu_transition_impl(
|
||||
platform: PlatformInfo.type,
|
||||
refs: struct.type,
|
||||
attrs: struct.type) -> PlatformInfo.type:
|
||||
return _cpu_split_transition_impl(platform, refs, attrs).values()[0]
|
||||
|
||||
cpu_split_transition = transition(
|
||||
impl = _cpu_split_transition_impl,
|
||||
refs = _REFS,
|
||||
attrs = [
|
||||
"cpu_filters",
|
||||
"min_sdk_version",
|
||||
],
|
||||
split = True,
|
||||
)
|
||||
|
||||
cpu_split_transition_instrumentation_test_apk = transition(
|
||||
impl = _cpu_split_transition_instrumentation_test_apk_impl,
|
||||
refs = _REFS,
|
||||
attrs = [
|
||||
"cpu_filters",
|
||||
"min_sdk_version",
|
||||
],
|
||||
split = True,
|
||||
)
|
||||
|
||||
# If our deps have been split-transitioned by CPU then we are already analyzing the dependency
|
||||
# graph using the resulting configurations. If there are any other attributes on the same target
|
||||
# that also need to analyze the dependency graph, then we want to use one of the configurations
|
||||
# from the split transition so that we don't end up analyzing the graph again using a different
|
||||
# configuration. This rule just picks the first configuration from the split-transition.
|
||||
#
|
||||
# This is used for the `manifest` attribute of `android_binary`.
|
||||
cpu_transition = transition(
|
||||
impl = _cpu_transition_impl,
|
||||
refs = _REFS,
|
||||
attrs = [
|
||||
"cpu_filters",
|
||||
"min_sdk_version",
|
||||
],
|
||||
)
|
||||
|
||||
def _do_not_build_only_native_code_transition(
|
||||
platform: PlatformInfo.type,
|
||||
refs: struct.type) -> PlatformInfo.type:
|
||||
constraints = dict(platform.configuration.constraints.items())
|
||||
constraints[refs.maybe_build_only_native_code[ConstraintSettingInfo].label] = refs.do_not_build_only_native_code[ConstraintValueInfo]
|
||||
|
||||
return PlatformInfo(
|
||||
label = platform.label,
|
||||
configuration = ConfigurationInfo(
|
||||
constraints = constraints,
|
||||
values = platform.configuration.values,
|
||||
),
|
||||
)
|
||||
|
||||
do_not_build_only_native_code_transition = transition(
|
||||
impl = _do_not_build_only_native_code_transition,
|
||||
refs = {
|
||||
"do_not_build_only_native_code": "fbsource//xplat/buck2/platform/android:do_not_build_only_native_code",
|
||||
"maybe_build_only_native_code": "fbsource//xplat/buck2/platform/android:maybe_build_only_native_code",
|
||||
},
|
||||
)
|
||||
|
||||
def get_deps_by_platform(ctx: "context") -> {str.type: ["dependency"]}:
|
||||
deps_by_platform = {}
|
||||
for dep_dict in ctx.attrs.deps:
|
||||
for platform, dep in dep_dict.items():
|
||||
deps = deps_by_platform.get(platform, [])
|
||||
deps.append(dep)
|
||||
deps_by_platform[platform] = deps
|
||||
|
||||
return deps_by_platform
|
||||
|
||||
def _get_min_sdk_constraint_value(min_sdk_version: int.type, refs: struct.type) -> ConstraintValueInfo.type:
|
||||
constraint_name = get_min_sdk_version_constraint_value_name(min_sdk_version)
|
||||
constraint = getattr(refs, constraint_name, None)
|
||||
if not constraint:
|
||||
fail("Unsupported min_sdk_version {}, please report!".format(min_sdk_version))
|
||||
|
||||
return constraint[ConstraintValueInfo]
|
||||
|
||||
def _is_building_android_binary() -> "selector":
|
||||
return select(
|
||||
{
|
||||
"DEFAULT": False,
|
||||
"prelude//os:building_android_binary": True,
|
||||
},
|
||||
)
|
||||
|
||||
def is_building_android_binary_attr() -> "attribute":
|
||||
return attrs.default_only(attrs.bool(default = _is_building_android_binary()))
|
||||
677
vendor/cxx/tools/buck/prelude/android/dex_rules.bzl
vendored
Normal file
677
vendor/cxx/tools/buck/prelude/android/dex_rules.bzl
vendored
Normal file
|
|
@ -0,0 +1,677 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load("@prelude//android:android_providers.bzl", "DexFilesInfo", "ExopackageDexInfo")
|
||||
load("@prelude//android:voltron.bzl", "ROOT_MODULE", "get_apk_module_graph_info", "get_root_module_only_apk_module_graph_info", "is_root_module")
|
||||
load("@prelude//java:dex.bzl", "get_dex_produced_from_java_library")
|
||||
load("@prelude//java:dex_toolchain.bzl", "DexToolchainInfo")
|
||||
load("@prelude//java:java_library.bzl", "compile_to_jar")
|
||||
load("@prelude//utils:utils.bzl", "expect", "flatten")
|
||||
load("@prelude//paths.bzl", "paths")
|
||||
|
||||
# Android builds use a tool called `d8` to compile Java bytecode is DEX (Dalvik EXecutable)
|
||||
# bytecode that runs on Android devices. Our Android builds have two distinct ways of
|
||||
# doing that:
|
||||
# 1) With pre-dexing enabled (this is the most common case for debug builds). That means that
|
||||
# d8 runs on every individual .jar file (to produce a .jar.dex file), and then at the APK
|
||||
# level we run d8 again to combine all the individual .jar.dex files.
|
||||
# 2) With pre-dexing disabled (this is the case if it is explicitly disabled, we are running
|
||||
# proguard, or we preprocess the java classes at the APK level). This means that we run
|
||||
# d8 at the APK level on all the .jar files.
|
||||
#
|
||||
# The .dex files that we package into the APK consist of a single classes.dex "primary DEX"
|
||||
# file, and N secondary DEX files. The classes that are put into the primary DEX are those
|
||||
# that are required at startup, and are specified via `primary_dex_patterns` (classes which
|
||||
# match one of those patterns are put into the primary DEX).
|
||||
#
|
||||
# The primary DEX is always stored in the root directory of the APK as `classes.dex`.
|
||||
#
|
||||
# We have 4 different ways of storing our secondary DEX files, which are specified via the
|
||||
# `dex_compression` attribute:
|
||||
# 1) `raw` compression. This means that we create `classes2.dex`, `classes3.dex`, ...,
|
||||
# `classesN.dex` and store each of them in the root directory of the APK.
|
||||
# 2) `jar` compression. For each secondary DEX file, we put a `classes.dex` entry into a
|
||||
# JAR file, and store it as an asset at `assets/secondary-program-dex-jars/secondary-I.dex.jar`
|
||||
# 3) `xz` compression. This is the same as `jar` compression, except that we run `xz` on the
|
||||
# JAR file to produce `assets/secondary-program-dex-jars/secondary-I.dex.jar.xz`.
|
||||
# 4) `xzs` compression. We do the same as `jar` compression, then concatenate all the jars
|
||||
# together and do `xz` compression on the result to produce a single
|
||||
# `assets/secondary-program-dex-jars/secondary.dex.jar.xzs`.
|
||||
#
|
||||
# For all compression types, we also package a `assets/secondary-program-dex-jars/metadata.txt`,
|
||||
# which has an entry for each secondary DEX file:
|
||||
# <secondary DEX file name> <sha1 hash of secondary DEX> <canary class name>
|
||||
#
|
||||
# A "canary class" is a Java class that we add to every secondary DEX. It is a known class that
|
||||
# can be used for DEX verification when loading the DEX on a device.
|
||||
#
|
||||
# For compression types other than raw, we also include a metadata file per secondary DEX, which
|
||||
# consists of a single line of the form:
|
||||
# jar:<size of secondary dex jar (in bytes)> dex:<size of uncompressed dex file (in bytes)>
|
||||
#
|
||||
# If an APK has Voltron modules, then we produce a separate group of secondary DEX files for each
|
||||
# module, and we put them into `assets/<module_name>` instead of `assets/secondary-program-dex-jars`.
|
||||
# We produce a `metadata.txt` file for each Voltron module.
|
||||
|
||||
_DEX_MERGE_OPTIONS = ["--no-desugar", "--no-optimize"]
|
||||
|
||||
SplitDexMergeConfig = record(
|
||||
dex_compression = str.type,
|
||||
primary_dex_patterns = [str.type],
|
||||
secondary_dex_weight_limit_bytes = int.type,
|
||||
)
|
||||
|
||||
def _get_dex_compression(ctx: "context") -> str.type:
|
||||
is_exopackage_enabled_for_secondary_dexes = "secondary_dex" in ctx.attrs.exopackage_modes
|
||||
default_dex_compression = "jar" if is_exopackage_enabled_for_secondary_dexes else "raw"
|
||||
dex_compression = ctx.attrs.dex_compression or default_dex_compression
|
||||
expect(
|
||||
dex_compression in ["raw", "jar", "xz", "xzs"],
|
||||
"Only 'raw', 'jar', 'xz' and 'xzs' dex compression are supported at this time!",
|
||||
)
|
||||
|
||||
return dex_compression
|
||||
|
||||
def get_split_dex_merge_config(
|
||||
ctx: "context",
|
||||
android_toolchain: "AndroidToolchainInfo") -> "SplitDexMergeConfig":
|
||||
return SplitDexMergeConfig(
|
||||
dex_compression = _get_dex_compression(ctx),
|
||||
primary_dex_patterns = ctx.attrs.primary_dex_patterns,
|
||||
secondary_dex_weight_limit_bytes = (
|
||||
ctx.attrs.secondary_dex_weight_limit or
|
||||
android_toolchain.secondary_dex_weight_limit
|
||||
),
|
||||
)
|
||||
|
||||
def get_single_primary_dex(
|
||||
ctx: "context",
|
||||
android_toolchain: "AndroidToolchainInfo",
|
||||
java_library_jars: ["artifact"],
|
||||
is_optimized: bool.type) -> "DexFilesInfo":
|
||||
expect(
|
||||
not _is_exopackage_enabled_for_secondary_dex(ctx),
|
||||
"It doesn't make sense to enable secondary dex exopackage for single dex builds!",
|
||||
)
|
||||
d8_cmd = cmd_args(android_toolchain.d8_command[RunInfo])
|
||||
|
||||
output_dex_file = ctx.actions.declare_output("classes.dex")
|
||||
d8_cmd.add(["--output-dex-file", output_dex_file.as_output()])
|
||||
|
||||
jar_to_dex_file = ctx.actions.write("jar_to_dex_file.txt", java_library_jars)
|
||||
d8_cmd.add(["--files-to-dex-list", jar_to_dex_file])
|
||||
d8_cmd.hidden(java_library_jars)
|
||||
|
||||
d8_cmd.add(["--android-jar", android_toolchain.android_jar])
|
||||
if not is_optimized:
|
||||
d8_cmd.add("--no-optimize")
|
||||
|
||||
ctx.actions.run(d8_cmd, category = "d8", identifier = "{}:{}".format(ctx.label.package, ctx.label.name))
|
||||
|
||||
return DexFilesInfo(
|
||||
primary_dex = output_dex_file,
|
||||
secondary_dex_dirs = [],
|
||||
secondary_dex_exopackage_info = None,
|
||||
proguard_text_files_path = None,
|
||||
primary_dex_class_names = None,
|
||||
)
|
||||
|
||||
def get_multi_dex(
|
||||
ctx: "context",
|
||||
android_toolchain: "AndroidToolchainInfo",
|
||||
java_library_jars_to_owners: {"artifact": "target_label"},
|
||||
primary_dex_patterns: [str.type],
|
||||
proguard_configuration_output_file: ["artifact", None],
|
||||
proguard_mapping_output_file: ["artifact", None],
|
||||
is_optimized: bool.type,
|
||||
apk_module_graph_file: ["artifact", None] = None) -> "DexFilesInfo":
|
||||
expect(
|
||||
not _is_exopackage_enabled_for_secondary_dex(ctx),
|
||||
"secondary dex exopackage can only be enabled on pre-dexed builds!",
|
||||
)
|
||||
primary_dex_file = ctx.actions.declare_output("classes.dex")
|
||||
primary_dex_class_names = ctx.actions.declare_output("primary_dex_class_names.txt")
|
||||
root_module_secondary_dex_output_dir = ctx.actions.declare_output("root_module_secondary_dex_output_dir")
|
||||
secondary_dex_dir = ctx.actions.declare_output("secondary_dex_output_dir")
|
||||
|
||||
# dynamic actions are not valid with no input, but it's easier to use the same code regardless,
|
||||
# so just create an empty input.
|
||||
inputs = [apk_module_graph_file] if apk_module_graph_file else [ctx.actions.write("empty_artifact_for_multi_dex_dynamic_action", [])]
|
||||
outputs = [primary_dex_file, primary_dex_class_names, root_module_secondary_dex_output_dir, secondary_dex_dir]
|
||||
|
||||
def do_multi_dex(ctx: "context", artifacts, outputs):
|
||||
apk_module_graph_info = get_apk_module_graph_info(ctx, apk_module_graph_file, artifacts) if apk_module_graph_file else get_root_module_only_apk_module_graph_info()
|
||||
target_to_module_mapping_function = apk_module_graph_info.target_to_module_mapping_function
|
||||
module_to_jars = {}
|
||||
for java_library_jar, owner in java_library_jars_to_owners.items():
|
||||
module = target_to_module_mapping_function(str(owner))
|
||||
module_to_jars.setdefault(module, []).append(java_library_jar)
|
||||
|
||||
secondary_dex_dir_srcs = {}
|
||||
for module, jars in module_to_jars.items():
|
||||
multi_dex_cmd = cmd_args(android_toolchain.multi_dex_command[RunInfo])
|
||||
|
||||
if is_root_module(module):
|
||||
multi_dex_cmd.add("--primary-dex", outputs[primary_dex_file].as_output())
|
||||
multi_dex_cmd.add("--primary-dex-patterns-path", ctx.actions.write("primary_dex_patterns", primary_dex_patterns))
|
||||
multi_dex_cmd.add("--primary-dex-class-names", outputs[primary_dex_class_names].as_output())
|
||||
multi_dex_cmd.add("--secondary-dex-output-dir", outputs[root_module_secondary_dex_output_dir].as_output())
|
||||
else:
|
||||
secondary_dex_dir_for_module = ctx.actions.declare_output("secondary_dex_output_dir_for_module_{}".format(module))
|
||||
secondary_dex_subdir = secondary_dex_dir_for_module.project(_get_secondary_dex_subdir(module))
|
||||
secondary_dex_dir_srcs[_get_secondary_dex_subdir(module)] = secondary_dex_subdir
|
||||
multi_dex_cmd.add("--secondary-dex-output-dir", secondary_dex_dir_for_module.as_output())
|
||||
multi_dex_cmd.add("--module-deps", ctx.actions.write("module_deps_for_{}".format(module), apk_module_graph_info.module_to_module_deps_function(module)))
|
||||
|
||||
multi_dex_cmd.add("--module", module)
|
||||
multi_dex_cmd.add("--canary-class-name", apk_module_graph_info.module_to_canary_class_name_function(module))
|
||||
|
||||
jar_to_dex_file = ctx.actions.write("jars_to_dex_file_for_module_{}.txt".format(module), jars)
|
||||
multi_dex_cmd.add("--files-to-dex-list", jar_to_dex_file)
|
||||
multi_dex_cmd.hidden(jars)
|
||||
|
||||
multi_dex_cmd.add("--android-jar", android_toolchain.android_jar)
|
||||
if not is_optimized:
|
||||
multi_dex_cmd.add("--no-optimize")
|
||||
|
||||
if proguard_configuration_output_file:
|
||||
multi_dex_cmd.add("--proguard-configuration-file", proguard_configuration_output_file)
|
||||
multi_dex_cmd.add("--proguard-mapping-file", proguard_mapping_output_file)
|
||||
|
||||
multi_dex_cmd.add("--compression", _get_dex_compression(ctx))
|
||||
multi_dex_cmd.add("--xz-compression-level", str(ctx.attrs.xz_compression_level))
|
||||
if ctx.attrs.minimize_primary_dex_size:
|
||||
multi_dex_cmd.add("--minimize-primary-dex")
|
||||
|
||||
ctx.actions.run(multi_dex_cmd, category = "multi_dex", identifier = "{}:{}_module_{}".format(ctx.label.package, ctx.label.name, module))
|
||||
|
||||
ctx.actions.symlinked_dir(outputs[secondary_dex_dir], secondary_dex_dir_srcs)
|
||||
|
||||
ctx.actions.dynamic_output(dynamic = inputs, inputs = [], outputs = outputs, f = do_multi_dex)
|
||||
|
||||
return DexFilesInfo(
|
||||
primary_dex = primary_dex_file,
|
||||
secondary_dex_dirs = [root_module_secondary_dex_output_dir, secondary_dex_dir],
|
||||
secondary_dex_exopackage_info = None,
|
||||
proguard_text_files_path = None,
|
||||
primary_dex_class_names = primary_dex_class_names,
|
||||
)
|
||||
|
||||
def merge_to_single_dex(
|
||||
ctx: "context",
|
||||
android_toolchain: "AndroidToolchainInfo",
|
||||
pre_dexed_libs: ["DexLibraryInfo"]) -> "DexFilesInfo":
|
||||
expect(
|
||||
not _is_exopackage_enabled_for_secondary_dex(ctx),
|
||||
"It doesn't make sense to enable secondary dex exopackage for single dex builds!",
|
||||
)
|
||||
output_dex_file = ctx.actions.declare_output("classes.dex")
|
||||
pre_dexed_artifacts_to_dex_file = ctx.actions.declare_output("pre_dexed_artifacts_to_dex_file.txt")
|
||||
pre_dexed_artifacts = [pre_dexed_lib.dex for pre_dexed_lib in pre_dexed_libs if pre_dexed_lib.dex != None]
|
||||
_merge_dexes(ctx, android_toolchain, output_dex_file, pre_dexed_artifacts, pre_dexed_artifacts_to_dex_file)
|
||||
|
||||
return DexFilesInfo(
|
||||
primary_dex = output_dex_file,
|
||||
secondary_dex_dirs = [],
|
||||
secondary_dex_exopackage_info = None,
|
||||
proguard_text_files_path = None,
|
||||
primary_dex_class_names = None,
|
||||
)
|
||||
|
||||
DexInputWithSpecifiedClasses = record(
|
||||
lib = "DexLibraryInfo",
|
||||
dex_class_names = [str.type],
|
||||
)
|
||||
|
||||
DexInputWithClassNamesFile = record(
|
||||
lib = "DexLibraryInfo",
|
||||
filtered_class_names_file = "artifact",
|
||||
)
|
||||
|
||||
# When using jar compression, the secondary dex directory consists of N secondary dex jars, each
|
||||
# of which has a corresponding .meta file (the secondary_dex_metadata_file) containing a single
|
||||
# line of the form:
|
||||
# jar:<size of secondary dex jar (in bytes)> dex:<size of uncompressed dex file (in bytes)>
|
||||
#
|
||||
# It also contains a metadata.txt file, which consists on N lines, one for each secondary dex
|
||||
# jar. Those lines consist of:
|
||||
# <secondary dex file name> <sha1 hash of secondary dex> <canary class>
|
||||
#
|
||||
# We write the line that needs to be added to metadata.txt for this secondary dex jar to
|
||||
# secondary_dex_metadata_line, and we use the secondary_dex_canary_class_name for the
|
||||
# <canary class>.
|
||||
#
|
||||
# When we have finished building all of the secondary dexes, we read each of the
|
||||
# secondary_dex_metadata_line artifacts and write them to a single metadata.txt file.
|
||||
# We do that for raw compression too, since it also has a metadata.txt file.
|
||||
SecondaryDexMetadataConfig = record(
|
||||
secondary_dex_compression = str.type,
|
||||
secondary_dex_metadata_path = [str.type, None],
|
||||
secondary_dex_metadata_file = ["artifact", None],
|
||||
secondary_dex_metadata_line = "artifact",
|
||||
secondary_dex_canary_class_name = str.type,
|
||||
)
|
||||
|
||||
def _get_secondary_dex_jar_metadata_config(
|
||||
actions: "actions",
|
||||
secondary_dex_path: str.type,
|
||||
module: str.type,
|
||||
module_to_canary_class_name_function: "function",
|
||||
index: int.type) -> SecondaryDexMetadataConfig.type:
|
||||
secondary_dex_metadata_path = secondary_dex_path + ".meta"
|
||||
return SecondaryDexMetadataConfig(
|
||||
secondary_dex_compression = "jar",
|
||||
secondary_dex_metadata_path = secondary_dex_metadata_path,
|
||||
secondary_dex_metadata_file = actions.declare_output(secondary_dex_metadata_path),
|
||||
secondary_dex_metadata_line = actions.declare_output("metadata_line_artifacts/{}/{}".format(module, index + 1)),
|
||||
secondary_dex_canary_class_name = _get_fully_qualified_canary_class_name(module, module_to_canary_class_name_function, index + 1),
|
||||
)
|
||||
|
||||
def _get_secondary_dex_raw_metadata_config(
|
||||
actions: "actions",
|
||||
module: str.type,
|
||||
module_to_canary_class_name_function: "function",
|
||||
index: int.type) -> SecondaryDexMetadataConfig.type:
|
||||
return SecondaryDexMetadataConfig(
|
||||
secondary_dex_compression = "raw",
|
||||
secondary_dex_metadata_path = None,
|
||||
secondary_dex_metadata_file = None,
|
||||
secondary_dex_metadata_line = actions.declare_output("metadata_line_artifacts/{}/{}".format(module, index + 1)),
|
||||
secondary_dex_canary_class_name = _get_fully_qualified_canary_class_name(module, module_to_canary_class_name_function, index + 1),
|
||||
)
|
||||
|
||||
def _get_filter_dex_batch_size() -> int.type:
|
||||
return 100
|
||||
|
||||
def _filter_pre_dexed_libs(
|
||||
actions: "actions",
|
||||
android_toolchain: "AndroidToolchainInfo",
|
||||
primary_dex_patterns_file: "artifact",
|
||||
pre_dexed_libs: ["DexLibraryInfo"],
|
||||
batch_number: int.type) -> [DexInputWithClassNamesFile.type]:
|
||||
pre_dexed_lib_with_class_names_files = []
|
||||
for pre_dexed_lib in pre_dexed_libs:
|
||||
class_names = pre_dexed_lib.class_names
|
||||
id = "{}_{}_{}".format(class_names.owner.package, class_names.owner.name, class_names.short_path)
|
||||
filtered_class_names_file = actions.declare_output("primary_dex_class_names_for_{}".format(id))
|
||||
pre_dexed_lib_with_class_names_files.append(
|
||||
DexInputWithClassNamesFile(lib = pre_dexed_lib, filtered_class_names_file = filtered_class_names_file),
|
||||
)
|
||||
|
||||
filter_dex_cmd = cmd_args([
|
||||
android_toolchain.filter_dex_class_names[RunInfo],
|
||||
"--primary-dex-patterns",
|
||||
primary_dex_patterns_file,
|
||||
"--class-names",
|
||||
[x.lib.class_names for x in pre_dexed_lib_with_class_names_files],
|
||||
"--output",
|
||||
[x.filtered_class_names_file.as_output() for x in pre_dexed_lib_with_class_names_files],
|
||||
])
|
||||
actions.run(filter_dex_cmd, category = "filter_dex", identifier = "batch_{}".format(batch_number))
|
||||
|
||||
return pre_dexed_lib_with_class_names_files
|
||||
|
||||
_SortedPreDexedInputs = record(
|
||||
module = str.type,
|
||||
primary_dex_inputs = [DexInputWithSpecifiedClasses.type],
|
||||
secondary_dex_inputs = [[DexInputWithSpecifiedClasses.type]],
|
||||
)
|
||||
|
||||
def merge_to_split_dex(
|
||||
ctx: "context",
|
||||
android_toolchain: "AndroidToolchainInfo",
|
||||
pre_dexed_libs: ["DexLibraryInfo"],
|
||||
split_dex_merge_config: "SplitDexMergeConfig",
|
||||
apk_module_graph_file: ["artifact", None] = None) -> "DexFilesInfo":
|
||||
is_exopackage_enabled_for_secondary_dex = _is_exopackage_enabled_for_secondary_dex(ctx)
|
||||
if is_exopackage_enabled_for_secondary_dex:
|
||||
expect(
|
||||
split_dex_merge_config.dex_compression == "jar",
|
||||
"Exopackage can only be enabled for secondary dexes when the dex compression is 'jar', but the dex compression is '{}'".format(split_dex_merge_config.dex_compression),
|
||||
)
|
||||
primary_dex_patterns_file = ctx.actions.write("primary_dex_patterns_file", split_dex_merge_config.primary_dex_patterns)
|
||||
|
||||
pre_dexed_lib_with_class_names_files = []
|
||||
|
||||
batch_size = _get_filter_dex_batch_size()
|
||||
for (batch_number, start_index) in enumerate(range(0, len(pre_dexed_libs), batch_size)):
|
||||
end_index = min(start_index + batch_size, len(pre_dexed_libs))
|
||||
pre_dexed_lib_with_class_names_files.extend(
|
||||
_filter_pre_dexed_libs(
|
||||
ctx.actions,
|
||||
android_toolchain,
|
||||
primary_dex_patterns_file,
|
||||
pre_dexed_libs[start_index:end_index],
|
||||
batch_number,
|
||||
),
|
||||
)
|
||||
|
||||
input_artifacts = flatten([[
|
||||
input.lib.dex,
|
||||
input.lib.weight_estimate,
|
||||
input.filtered_class_names_file,
|
||||
] for input in pre_dexed_lib_with_class_names_files]) + ([apk_module_graph_file] if apk_module_graph_file else [])
|
||||
primary_dex_artifact_list = ctx.actions.declare_output("pre_dexed_artifacts_for_primary_dex.txt")
|
||||
primary_dex_output = ctx.actions.declare_output("classes.dex")
|
||||
primary_dex_class_names_list = ctx.actions.declare_output("primary_dex_class_names_list.txt")
|
||||
root_module_secondary_dexes_dir = ctx.actions.declare_output("root_module_secondary_dexes_dir")
|
||||
root_module_secondary_dexes_subdir = root_module_secondary_dexes_dir.project(_get_secondary_dex_subdir(ROOT_MODULE))
|
||||
root_module_secondary_dexes_metadata = root_module_secondary_dexes_dir.project(paths.join(_get_secondary_dex_subdir(ROOT_MODULE), "metadata.txt"))
|
||||
non_root_module_secondary_dexes_dir = ctx.actions.declare_output("non_root_module_secondary_dexes_dir")
|
||||
|
||||
outputs = [primary_dex_output, primary_dex_artifact_list, primary_dex_class_names_list, root_module_secondary_dexes_dir, non_root_module_secondary_dexes_dir]
|
||||
|
||||
def merge_pre_dexed_libs(ctx: "context", artifacts, outputs):
|
||||
apk_module_graph_info = get_apk_module_graph_info(ctx, apk_module_graph_file, artifacts) if apk_module_graph_file else get_root_module_only_apk_module_graph_info()
|
||||
module_to_canary_class_name_function = apk_module_graph_info.module_to_canary_class_name_function
|
||||
sorted_pre_dexed_inputs = _sort_pre_dexed_files(
|
||||
ctx,
|
||||
artifacts,
|
||||
pre_dexed_lib_with_class_names_files,
|
||||
split_dex_merge_config,
|
||||
get_module_from_target = apk_module_graph_info.target_to_module_mapping_function,
|
||||
module_to_canary_class_name_function = module_to_canary_class_name_function,
|
||||
)
|
||||
|
||||
root_module_secondary_dexes_for_symlinking = {}
|
||||
non_root_module_secondary_dexes_for_symlinking = {}
|
||||
metadata_line_artifacts_by_module = {}
|
||||
metadata_dot_txt_files_by_module = {}
|
||||
|
||||
for sorted_pre_dexed_input in sorted_pre_dexed_inputs:
|
||||
module = sorted_pre_dexed_input.module
|
||||
secondary_dexes_for_symlinking = root_module_secondary_dexes_for_symlinking if is_root_module(module) else non_root_module_secondary_dexes_for_symlinking
|
||||
primary_dex_inputs = sorted_pre_dexed_input.primary_dex_inputs
|
||||
pre_dexed_artifacts = [primary_dex_input.lib.dex for primary_dex_input in primary_dex_inputs if primary_dex_input.lib.dex]
|
||||
if pre_dexed_artifacts:
|
||||
expect(is_root_module(module), "module {} should not have a primary dex!".format(module))
|
||||
ctx.actions.write(
|
||||
outputs[primary_dex_class_names_list].as_output(),
|
||||
flatten([primary_dex_input.dex_class_names for primary_dex_input in primary_dex_inputs]),
|
||||
)
|
||||
|
||||
_merge_dexes(
|
||||
ctx,
|
||||
android_toolchain,
|
||||
outputs[primary_dex_output],
|
||||
pre_dexed_artifacts,
|
||||
outputs[primary_dex_artifact_list],
|
||||
class_names_to_include = primary_dex_class_names_list,
|
||||
)
|
||||
else:
|
||||
expect(
|
||||
not is_root_module(module),
|
||||
"No primary dex classes were specified! Please add primary_dex_patterns to ensure that at least one class exists in the primary dex.",
|
||||
)
|
||||
|
||||
secondary_dex_inputs = sorted_pre_dexed_input.secondary_dex_inputs
|
||||
raw_secondary_dexes_for_compressing = {}
|
||||
for i in range(len(secondary_dex_inputs)):
|
||||
if split_dex_merge_config.dex_compression == "jar" or split_dex_merge_config.dex_compression == "raw":
|
||||
if split_dex_merge_config.dex_compression == "jar":
|
||||
secondary_dex_path = _get_jar_secondary_dex_path(i, module)
|
||||
secondary_dex_metadata_config = _get_secondary_dex_jar_metadata_config(ctx.actions, secondary_dex_path, module, module_to_canary_class_name_function, i)
|
||||
secondary_dexes_for_symlinking[secondary_dex_metadata_config.secondary_dex_metadata_path] = secondary_dex_metadata_config.secondary_dex_metadata_file
|
||||
else:
|
||||
secondary_dex_path = _get_raw_secondary_dex_path(i, module)
|
||||
secondary_dex_metadata_config = _get_secondary_dex_raw_metadata_config(ctx.actions, module, module_to_canary_class_name_function, i)
|
||||
|
||||
secondary_dex_output = ctx.actions.declare_output(secondary_dex_path)
|
||||
secondary_dexes_for_symlinking[secondary_dex_path] = secondary_dex_output
|
||||
metadata_line_artifacts_by_module.setdefault(module, []).append(secondary_dex_metadata_config.secondary_dex_metadata_line)
|
||||
else:
|
||||
secondary_dex_name = _get_raw_secondary_dex_name(i, module)
|
||||
secondary_dex_output = ctx.actions.declare_output("{}/{}".format(module, secondary_dex_name))
|
||||
raw_secondary_dexes_for_compressing[secondary_dex_name] = secondary_dex_output
|
||||
secondary_dex_metadata_config = None
|
||||
|
||||
secondary_dex_artifact_list = ctx.actions.declare_output("pre_dexed_artifacts_for_secondary_dex_{}_for_module_{}.txt".format(i + 2, module))
|
||||
secondary_dex_class_list = ctx.actions.write(
|
||||
"class_list_for_secondary_dex_{}_for_module_{}.txt".format(i + 2, module),
|
||||
flatten([secondary_dex_input.dex_class_names for secondary_dex_input in secondary_dex_inputs[i]]),
|
||||
)
|
||||
pre_dexed_artifacts = [secondary_dex_input.lib.dex for secondary_dex_input in secondary_dex_inputs[i] if secondary_dex_input.lib.dex]
|
||||
_merge_dexes(
|
||||
ctx,
|
||||
android_toolchain,
|
||||
secondary_dex_output,
|
||||
pre_dexed_artifacts,
|
||||
secondary_dex_artifact_list,
|
||||
class_names_to_include = secondary_dex_class_list,
|
||||
secondary_dex_metadata_config = secondary_dex_metadata_config,
|
||||
)
|
||||
|
||||
if split_dex_merge_config.dex_compression == "jar" or split_dex_merge_config.dex_compression == "raw":
|
||||
metadata_dot_txt_path = "{}/metadata.txt".format(_get_secondary_dex_subdir(module))
|
||||
metadata_dot_txt_file = ctx.actions.declare_output(metadata_dot_txt_path)
|
||||
secondary_dexes_for_symlinking[metadata_dot_txt_path] = metadata_dot_txt_file
|
||||
metadata_dot_txt_files_by_module[module] = metadata_dot_txt_file
|
||||
else:
|
||||
raw_secondary_dexes_dir = ctx.actions.symlinked_dir("raw_secondary_dexes_dir_for_module_{}".format(module), raw_secondary_dexes_for_compressing)
|
||||
secondary_dex_dir_for_module = ctx.actions.declare_output("secondary_dexes_dir_for_{}".format(module))
|
||||
secondary_dex_subdir = secondary_dex_dir_for_module.project(_get_secondary_dex_subdir(module))
|
||||
|
||||
multi_dex_cmd = cmd_args(android_toolchain.multi_dex_command[RunInfo])
|
||||
multi_dex_cmd.add("--secondary-dex-output-dir", secondary_dex_dir_for_module.as_output())
|
||||
multi_dex_cmd.add("--raw-secondary-dexes-dir", raw_secondary_dexes_dir)
|
||||
multi_dex_cmd.add("--compression", _get_dex_compression(ctx))
|
||||
multi_dex_cmd.add("--xz-compression-level", str(ctx.attrs.xz_compression_level))
|
||||
multi_dex_cmd.add("--module", module)
|
||||
multi_dex_cmd.add("--canary-class-name", module_to_canary_class_name_function(module))
|
||||
if not is_root_module(module):
|
||||
multi_dex_cmd.add("--module-deps", ctx.actions.write("module_deps_for_{}".format(module), apk_module_graph_info.module_to_module_deps_function(module)))
|
||||
|
||||
ctx.actions.run(multi_dex_cmd, category = "multi_dex_from_raw_dexes", identifier = "{}:{}_module_{}".format(ctx.label.package, ctx.label.name, module))
|
||||
|
||||
secondary_dexes_for_symlinking[_get_secondary_dex_subdir(module)] = secondary_dex_subdir
|
||||
|
||||
if metadata_dot_txt_files_by_module:
|
||||
def write_metadata_dot_txts(ctx: "context", artifacts, outputs):
|
||||
for voltron_module, metadata_dot_txt in metadata_dot_txt_files_by_module.items():
|
||||
metadata_line_artifacts = metadata_line_artifacts_by_module[voltron_module]
|
||||
expect(metadata_line_artifacts != None, "Should have metadata lines!")
|
||||
|
||||
metadata_lines = [".id {}".format(voltron_module)]
|
||||
metadata_lines.extend([".requires {}".format(module_dep) for module_dep in apk_module_graph_info.module_to_module_deps_function(voltron_module)])
|
||||
if split_dex_merge_config.dex_compression == "raw" and is_root_module(voltron_module):
|
||||
metadata_lines.append(".root_relative")
|
||||
for metadata_line_artifact in metadata_line_artifacts:
|
||||
metadata_lines.append(artifacts[metadata_line_artifact].read_string().strip())
|
||||
ctx.actions.write(outputs[metadata_dot_txt], metadata_lines)
|
||||
|
||||
ctx.actions.dynamic_output(dynamic = flatten(metadata_line_artifacts_by_module.values()), inputs = [], outputs = metadata_dot_txt_files_by_module.values(), f = write_metadata_dot_txts)
|
||||
|
||||
ctx.actions.symlinked_dir(
|
||||
outputs[root_module_secondary_dexes_dir],
|
||||
root_module_secondary_dexes_for_symlinking,
|
||||
)
|
||||
ctx.actions.symlinked_dir(
|
||||
outputs[non_root_module_secondary_dexes_dir],
|
||||
non_root_module_secondary_dexes_for_symlinking,
|
||||
)
|
||||
|
||||
ctx.actions.dynamic_output(dynamic = input_artifacts, inputs = [], outputs = outputs, f = merge_pre_dexed_libs)
|
||||
|
||||
if is_exopackage_enabled_for_secondary_dex:
|
||||
secondary_dex_dirs = [non_root_module_secondary_dexes_dir]
|
||||
secondary_dex_exopackage_info = ExopackageDexInfo(
|
||||
metadata = root_module_secondary_dexes_metadata,
|
||||
directory = root_module_secondary_dexes_subdir,
|
||||
)
|
||||
else:
|
||||
secondary_dex_dirs = [root_module_secondary_dexes_dir, non_root_module_secondary_dexes_dir]
|
||||
secondary_dex_exopackage_info = None
|
||||
|
||||
return DexFilesInfo(
|
||||
primary_dex = primary_dex_output,
|
||||
secondary_dex_dirs = secondary_dex_dirs,
|
||||
secondary_dex_exopackage_info = secondary_dex_exopackage_info,
|
||||
proguard_text_files_path = None,
|
||||
primary_dex_class_names = primary_dex_class_names_list,
|
||||
)
|
||||
|
||||
def _merge_dexes(
|
||||
ctx: "context",
|
||||
android_toolchain: "AndroidToolchainInfo",
|
||||
output_dex_file: "artifact",
|
||||
pre_dexed_artifacts: ["artifact"],
|
||||
pre_dexed_artifacts_file: "artifact",
|
||||
class_names_to_include: ["artifact", None] = None,
|
||||
secondary_output_dex_file: ["artifact", None] = None,
|
||||
secondary_dex_metadata_config: [SecondaryDexMetadataConfig.type, None] = None):
|
||||
d8_cmd = cmd_args(android_toolchain.d8_command[RunInfo])
|
||||
d8_cmd.add(["--output-dex-file", output_dex_file.as_output()])
|
||||
|
||||
pre_dexed_artifacts_to_dex_file = ctx.actions.write(pre_dexed_artifacts_file.as_output(), pre_dexed_artifacts)
|
||||
d8_cmd.add(["--files-to-dex-list", pre_dexed_artifacts_to_dex_file])
|
||||
d8_cmd.hidden(pre_dexed_artifacts)
|
||||
|
||||
d8_cmd.add(["--android-jar", android_toolchain.android_jar])
|
||||
d8_cmd.add(_DEX_MERGE_OPTIONS)
|
||||
|
||||
if class_names_to_include:
|
||||
d8_cmd.add(["--primary-dex-class-names-path", class_names_to_include])
|
||||
|
||||
if secondary_output_dex_file:
|
||||
d8_cmd.add(["--secondary-output-dex-file", secondary_output_dex_file.as_output()])
|
||||
|
||||
if secondary_dex_metadata_config:
|
||||
d8_cmd.add(["--secondary-dex-compression", secondary_dex_metadata_config.secondary_dex_compression])
|
||||
if secondary_dex_metadata_config.secondary_dex_metadata_file:
|
||||
d8_cmd.add(["--secondary-dex-metadata-file", secondary_dex_metadata_config.secondary_dex_metadata_file.as_output()])
|
||||
d8_cmd.add(["--secondary-dex-metadata-line", secondary_dex_metadata_config.secondary_dex_metadata_line.as_output()])
|
||||
d8_cmd.add(["--secondary-dex-canary-class-name", secondary_dex_metadata_config.secondary_dex_canary_class_name])
|
||||
|
||||
ctx.actions.run(
|
||||
d8_cmd,
|
||||
category = "d8",
|
||||
identifier = "{}:{} {}".format(ctx.label.package, ctx.label.name, output_dex_file.short_path),
|
||||
)
|
||||
|
||||
def _sort_pre_dexed_files(
|
||||
ctx: "context",
|
||||
artifacts,
|
||||
pre_dexed_lib_with_class_names_files: ["DexInputWithClassNamesFile"],
|
||||
split_dex_merge_config: "SplitDexMergeConfig",
|
||||
get_module_from_target: "function",
|
||||
module_to_canary_class_name_function: "function") -> [_SortedPreDexedInputs.type]:
|
||||
sorted_pre_dexed_inputs_map = {}
|
||||
current_secondary_dex_size_map = {}
|
||||
current_secondary_dex_inputs_map = {}
|
||||
for pre_dexed_lib_with_class_names_file in pre_dexed_lib_with_class_names_files:
|
||||
pre_dexed_lib = pre_dexed_lib_with_class_names_file.lib
|
||||
module = get_module_from_target(str(pre_dexed_lib.dex.owner.raw_target()))
|
||||
primary_dex_data, secondary_dex_data = artifacts[pre_dexed_lib_with_class_names_file.filtered_class_names_file].read_string().split(";")
|
||||
primary_dex_class_names = primary_dex_data.split(",") if primary_dex_data else []
|
||||
secondary_dex_class_names = secondary_dex_data.split(",") if secondary_dex_data else []
|
||||
|
||||
module_pre_dexed_inputs = sorted_pre_dexed_inputs_map.setdefault(module, _SortedPreDexedInputs(
|
||||
module = module,
|
||||
primary_dex_inputs = [],
|
||||
secondary_dex_inputs = [],
|
||||
))
|
||||
|
||||
primary_dex_inputs = module_pre_dexed_inputs.primary_dex_inputs
|
||||
secondary_dex_inputs = module_pre_dexed_inputs.secondary_dex_inputs
|
||||
|
||||
if len(primary_dex_class_names) > 0:
|
||||
expect(
|
||||
is_root_module(module),
|
||||
"Non-root modules should not have anything that belongs in the primary dex, " +
|
||||
"but {} is assigned to module {} and has the following class names in the primary dex: {}\n".format(
|
||||
pre_dexed_lib.dex.owner,
|
||||
module,
|
||||
"\n".join(primary_dex_class_names),
|
||||
),
|
||||
)
|
||||
primary_dex_inputs.append(
|
||||
DexInputWithSpecifiedClasses(lib = pre_dexed_lib, dex_class_names = primary_dex_class_names),
|
||||
)
|
||||
|
||||
if len(secondary_dex_class_names) > 0:
|
||||
weight_estimate = int(artifacts[pre_dexed_lib.weight_estimate].read_string().strip())
|
||||
current_secondary_dex_size = current_secondary_dex_size_map.get(module, 0)
|
||||
if current_secondary_dex_size + weight_estimate > split_dex_merge_config.secondary_dex_weight_limit_bytes:
|
||||
current_secondary_dex_size = 0
|
||||
current_secondary_dex_inputs_map[module] = []
|
||||
|
||||
current_secondary_dex_inputs = current_secondary_dex_inputs_map.setdefault(module, [])
|
||||
if len(current_secondary_dex_inputs) == 0:
|
||||
canary_class_dex_input = _create_canary_class(
|
||||
ctx,
|
||||
len(secondary_dex_inputs) + 1,
|
||||
module,
|
||||
module_to_canary_class_name_function,
|
||||
ctx.attrs._dex_toolchain[DexToolchainInfo],
|
||||
)
|
||||
current_secondary_dex_inputs.append(canary_class_dex_input)
|
||||
secondary_dex_inputs.append(current_secondary_dex_inputs)
|
||||
|
||||
current_secondary_dex_size_map[module] = current_secondary_dex_size + weight_estimate
|
||||
current_secondary_dex_inputs.append(
|
||||
DexInputWithSpecifiedClasses(lib = pre_dexed_lib, dex_class_names = secondary_dex_class_names),
|
||||
)
|
||||
|
||||
return sorted_pre_dexed_inputs_map.values()
|
||||
|
||||
def _get_raw_secondary_dex_name(index: int.type, module: str.type) -> str.type:
|
||||
# Root module begins at 2 (primary classes.dex is 1)
|
||||
# Non-root module begins at 1 (classes.dex)
|
||||
if is_root_module(module):
|
||||
return "classes{}.dex".format(index + 2)
|
||||
elif index == 0:
|
||||
return "classes.dex".format(module)
|
||||
else:
|
||||
return "classes{}.dex".format(module, index + 1)
|
||||
|
||||
def _get_raw_secondary_dex_path(index: int.type, module: str.type):
|
||||
if is_root_module(module):
|
||||
return _get_raw_secondary_dex_name(index, module)
|
||||
else:
|
||||
return "assets/{}/{}".format(module, _get_raw_secondary_dex_name(index, module))
|
||||
|
||||
def _get_jar_secondary_dex_path(index: int.type, module: str.type):
|
||||
return "{}/{}-{}.dex.jar".format(
|
||||
_get_secondary_dex_subdir(module),
|
||||
"secondary" if is_root_module(module) else module,
|
||||
index + 1,
|
||||
)
|
||||
|
||||
def _get_secondary_dex_subdir(module: str.type):
|
||||
return "assets/{}".format("secondary-program-dex-jars" if is_root_module(module) else module)
|
||||
|
||||
# We create "canary" classes and add them to each secondary dex jar to ensure each jar has a class
|
||||
# that can be safely loaded on any system. This class is used during secondary dex verification.
|
||||
_CANARY_FULLY_QUALIFIED_CLASS_NAME_TEMPLATE = "{}.dex{}.Canary"
|
||||
_CANARY_FILE_NAME_TEMPLATE = "canary_classes/{}/dex{}/Canary.java"
|
||||
_CANARY_CLASS_PACKAGE_TEMPLATE = "package {}.dex{};\n"
|
||||
_CANARY_CLASS_INTERFACE_DEFINITION = "public interface Canary {}"
|
||||
|
||||
def _create_canary_class(
|
||||
ctx: "context",
|
||||
index: int.type,
|
||||
module: str.type,
|
||||
module_to_canary_class_name_function: "function",
|
||||
dex_toolchain: DexToolchainInfo.type) -> DexInputWithSpecifiedClasses.type:
|
||||
prefix = module_to_canary_class_name_function(module)
|
||||
canary_class_java_file = ctx.actions.write(_CANARY_FILE_NAME_TEMPLATE.format(prefix, index), [_CANARY_CLASS_PACKAGE_TEMPLATE.format(prefix, index), _CANARY_CLASS_INTERFACE_DEFINITION])
|
||||
canary_class_jar = ctx.actions.declare_output("canary_classes/{}/canary_jar_{}.jar".format(prefix, index))
|
||||
compile_to_jar(ctx, [canary_class_java_file], output = canary_class_jar, actions_prefix = "{}_canary_class{}".format(prefix, index))
|
||||
|
||||
dex_library_info = get_dex_produced_from_java_library(ctx, dex_toolchain = dex_toolchain, jar_to_dex = canary_class_jar)
|
||||
|
||||
return DexInputWithSpecifiedClasses(
|
||||
lib = dex_library_info,
|
||||
dex_class_names = [_get_fully_qualified_canary_class_name(module, module_to_canary_class_name_function, index).replace(".", "/") + ".class"],
|
||||
)
|
||||
|
||||
def _get_fully_qualified_canary_class_name(module: str.type, module_to_canary_class_name_function: "function", index: int.type) -> str.type:
|
||||
prefix = module_to_canary_class_name_function(module)
|
||||
return _CANARY_FULLY_QUALIFIED_CLASS_NAME_TEMPLATE.format(prefix, index)
|
||||
|
||||
def _is_exopackage_enabled_for_secondary_dex(ctx: "context") -> bool.type:
|
||||
return "secondary_dex" in getattr(ctx.attrs, "exopackage_modes", [])
|
||||
27
vendor/cxx/tools/buck/prelude/android/exopackage.bzl
vendored
Normal file
27
vendor/cxx/tools/buck/prelude/android/exopackage.bzl
vendored
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
SECONDARY_DEX = 1
|
||||
NATIVE_LIBRARY = 2
|
||||
RESOURCES = 4
|
||||
MODULES = 8
|
||||
ARCH64 = 16
|
||||
|
||||
def get_exopackage_flags(exopackage_modes: [str.type]) -> int.type:
|
||||
flags = 0
|
||||
|
||||
for (name, flag) in [
|
||||
("secondary_dex", SECONDARY_DEX),
|
||||
("native_library", NATIVE_LIBRARY),
|
||||
("resources", RESOURCES),
|
||||
("modules", MODULES),
|
||||
("arch64", ARCH64),
|
||||
]:
|
||||
if name in exopackage_modes:
|
||||
flags += flag
|
||||
|
||||
return flags
|
||||
57
vendor/cxx/tools/buck/prelude/android/gen_aidl.bzl
vendored
Normal file
57
vendor/cxx/tools/buck/prelude/android/gen_aidl.bzl
vendored
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load("@prelude//java:java_toolchain.bzl", "JavaToolchainInfo")
|
||||
load(":android_toolchain.bzl", "AndroidToolchainInfo")
|
||||
|
||||
_AidlSourceInfo = provider(fields = [
|
||||
"srcs",
|
||||
])
|
||||
|
||||
def gen_aidl_impl(ctx: "context") -> ["provider"]:
|
||||
android_toolchain = ctx.attrs._android_toolchain[AndroidToolchainInfo]
|
||||
aidl_cmd = cmd_args(android_toolchain.aidl)
|
||||
aidl_cmd.add("-p", android_toolchain.framework_aidl_file)
|
||||
aidl_cmd.add("-I", ctx.attrs.import_path)
|
||||
for path in ctx.attrs.import_paths:
|
||||
aidl_cmd.add("-I", path)
|
||||
|
||||
# We need the `aidl_srcs` files - otherwise the search on the `import_path` won't find anything.
|
||||
aidl_cmd.hidden(ctx.attrs.aidl_srcs)
|
||||
|
||||
# Allow gen_aidl rules to depend on other gen_aidl rules, and make the source files from the
|
||||
# deps accessible in this context. This is an alternative to adding dependent files in
|
||||
# aidl_srcs.
|
||||
dep_srcs = []
|
||||
for dep in ctx.attrs.deps:
|
||||
source_info = dep.get(_AidlSourceInfo)
|
||||
if source_info != None:
|
||||
dep_srcs += source_info.srcs
|
||||
else:
|
||||
warning("`{}` dependency `{}` is not a `gen_aidl` rule and will be ignored".format(ctx.label, dep.label))
|
||||
|
||||
aidl_cmd.hidden(dep_srcs)
|
||||
|
||||
aidl_out = ctx.actions.declare_output("aidl_output")
|
||||
aidl_cmd.add("-o", aidl_out.as_output())
|
||||
aidl_cmd.add(ctx.attrs.aidl)
|
||||
ctx.actions.run(aidl_cmd, category = "aidl")
|
||||
|
||||
# Put the generated Java files into a zip file to be used as srcs to other rules.
|
||||
java_toolchain = ctx.attrs._java_toolchain[JavaToolchainInfo]
|
||||
jar_cmd = cmd_args(java_toolchain.jar)
|
||||
jar_cmd.add("-cfM")
|
||||
out = ctx.actions.declare_output("{}_aidl_java_output.src.zip".format(ctx.attrs.name))
|
||||
jar_cmd.add(out.as_output())
|
||||
jar_cmd.add(aidl_out)
|
||||
|
||||
ctx.actions.run(jar_cmd, category = "aidl_jar")
|
||||
|
||||
return [
|
||||
DefaultInfo(default_outputs = [out]),
|
||||
_AidlSourceInfo(srcs = [ctx.attrs.aidl] + ctx.attrs.aidl_srcs + dep_srcs),
|
||||
]
|
||||
15
vendor/cxx/tools/buck/prelude/android/min_sdk_version.bzl
vendored
Normal file
15
vendor/cxx/tools/buck/prelude/android/min_sdk_version.bzl
vendored
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
_MIN_SDK_VERSION = 19
|
||||
_MAX_SDK_VERSION = 33
|
||||
|
||||
def get_min_sdk_version_constraint_value_name(min_sdk: int.type) -> str.type:
|
||||
return "min_sdk_version_{}".format(min_sdk)
|
||||
|
||||
def get_min_sdk_version_range() -> range.type:
|
||||
return range(_MIN_SDK_VERSION, _MAX_SDK_VERSION)
|
||||
38
vendor/cxx/tools/buck/prelude/android/prebuilt_native_library.bzl
vendored
Normal file
38
vendor/cxx/tools/buck/prelude/android/prebuilt_native_library.bzl
vendored
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load(
|
||||
"@prelude//android:android_providers.bzl",
|
||||
"PrebuiltNativeLibraryDir",
|
||||
"merge_android_packageable_info",
|
||||
)
|
||||
|
||||
def prebuilt_native_library_impl(ctx: "context") -> ["provider"]:
|
||||
if ctx.attrs.is_asset and ctx.attrs.has_wrap_script:
|
||||
fail("Cannot use `is_asset` and `has_wrap_script` in the same rule")
|
||||
|
||||
prebuilt_native_library_dir = PrebuiltNativeLibraryDir(
|
||||
raw_target = ctx.label.raw_target(),
|
||||
dir = ctx.attrs.native_libs,
|
||||
for_primary_apk = ctx.attrs.has_wrap_script,
|
||||
is_asset = ctx.attrs.is_asset,
|
||||
)
|
||||
android_packageable_info = merge_android_packageable_info(
|
||||
ctx.label,
|
||||
ctx.actions,
|
||||
ctx.attrs.deps,
|
||||
prebuilt_native_library_dir = prebuilt_native_library_dir,
|
||||
)
|
||||
return [
|
||||
# Buck1 copies the input directory and returns it as the output path. We don't
|
||||
# copy; we could just return the input directory itself as the output path, but
|
||||
# we're avoiding that (due to potential confusion from the output path being an
|
||||
# input directory) until we have an actual need for prebuilt_native_library
|
||||
# having an output path.
|
||||
DefaultInfo(),
|
||||
android_packageable_info,
|
||||
]
|
||||
55
vendor/cxx/tools/buck/prelude/android/preprocess_java_classes.bzl
vendored
Normal file
55
vendor/cxx/tools/buck/prelude/android/preprocess_java_classes.bzl
vendored
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load("@prelude//android:android_toolchain.bzl", "AndroidToolchainInfo")
|
||||
load("@prelude//java/utils:java_utils.bzl", "get_path_separator")
|
||||
load("@prelude//utils:utils.bzl", "expect")
|
||||
|
||||
def get_preprocessed_java_classes(ctx: "context", input_jars = {"artifact": "target_label"}) -> {"artifact": "target_label"}:
|
||||
sh_script, _ = ctx.actions.write(
|
||||
"preprocessed_java_classes/script.sh",
|
||||
cmd_args(ctx.attrs.preprocess_java_classes_bash),
|
||||
is_executable = True,
|
||||
allow_args = True,
|
||||
)
|
||||
|
||||
preprocess_cmd = cmd_args(["/bin/bash", sh_script])
|
||||
preprocess_cmd.hidden(cmd_args(ctx.attrs.preprocess_java_classes_bash))
|
||||
for dep in ctx.attrs.preprocess_java_classes_deps:
|
||||
preprocess_cmd.hidden(dep[DefaultInfo].default_outputs + dep[DefaultInfo].other_outputs)
|
||||
|
||||
input_srcs = {}
|
||||
output_jars = {}
|
||||
|
||||
for i, (input_jar, target_label) in enumerate(input_jars.items()):
|
||||
expect(input_jar.extension == ".jar", "Expected {} to have extension .jar!".format(input_jar))
|
||||
jar_name = "{}_{}".format(i, input_jar.basename)
|
||||
input_srcs[jar_name] = input_jar
|
||||
output_jar = ctx.actions.declare_output(
|
||||
"preprocessed_java_classes/output_dir/{}".format(jar_name),
|
||||
)
|
||||
output_jars[output_jar] = target_label
|
||||
preprocess_cmd.hidden(output_jar.as_output())
|
||||
|
||||
if not output_jars:
|
||||
return {}
|
||||
|
||||
input_dir = ctx.actions.symlinked_dir("preprocessed_java_classes/input_dir", input_srcs)
|
||||
output_dir = cmd_args(output_jars.keys()[0].as_output()).parent()
|
||||
|
||||
env = {
|
||||
"ANDROID_BOOTCLASSPATH": cmd_args(
|
||||
ctx.attrs._android_toolchain[AndroidToolchainInfo].android_bootclasspath,
|
||||
delimiter = get_path_separator(),
|
||||
),
|
||||
"IN_JARS_DIR": cmd_args(input_dir),
|
||||
"OUT_JARS_DIR": output_dir,
|
||||
}
|
||||
|
||||
ctx.actions.run(preprocess_cmd, env = env, category = "preprocess_java_classes")
|
||||
|
||||
return output_jars
|
||||
168
vendor/cxx/tools/buck/prelude/android/proguard.bzl
vendored
Normal file
168
vendor/cxx/tools/buck/prelude/android/proguard.bzl
vendored
Normal file
|
|
@ -0,0 +1,168 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load("@prelude//android:android_toolchain.bzl", "AndroidToolchainInfo")
|
||||
load("@prelude//java:java_toolchain.bzl", "JavaToolchainInfo")
|
||||
load("@prelude//java/utils:java_utils.bzl", "get_path_separator")
|
||||
load("@prelude//utils:utils.bzl", "expect")
|
||||
|
||||
_UNSCRUBBED_JARS_DIR = "unscrubbed"
|
||||
|
||||
ProguardOutput = record(
|
||||
jars_to_owners = {"artifact": "target_label"},
|
||||
proguard_configuration_output_file = ["artifact", None],
|
||||
proguard_mapping_output_file = "artifact",
|
||||
proguard_artifacts = ["artifact"],
|
||||
)
|
||||
|
||||
def _get_proguard_command_line_args(
|
||||
ctx: "context",
|
||||
inputs_to_unscrubbed_outputs: {"artifact": "artifact"},
|
||||
proguard_configs: ["artifact"],
|
||||
mapping: "artifact",
|
||||
configuration: ["artifact", None],
|
||||
seeds: ["artifact", None],
|
||||
usage: ["artifact", None],
|
||||
android_toolchain: "AndroidToolchainInfo") -> "cmd_args":
|
||||
cmd = cmd_args()
|
||||
cmd.add("-basedirectory", "<user.dir>")
|
||||
|
||||
android_sdk_proguard_config = ctx.attrs.android_sdk_proguard_config or "none"
|
||||
if android_sdk_proguard_config == "optimized":
|
||||
cmd.add("-include", android_toolchain.optimized_proguard_config)
|
||||
cmd.add("-optimizationpasses", str(ctx.attrs.optimization_passes))
|
||||
elif android_sdk_proguard_config == "default":
|
||||
cmd.add("-include", android_toolchain.proguard_config)
|
||||
else:
|
||||
expect(android_sdk_proguard_config == "none")
|
||||
|
||||
for proguard_config in dedupe(proguard_configs):
|
||||
cmd.add("-include")
|
||||
cmd.add(cmd_args("\"", proguard_config, "\"", delimiter = ""))
|
||||
|
||||
for jar_input, jar_output in inputs_to_unscrubbed_outputs.items():
|
||||
cmd.add("-injar", jar_input, "-outjar", jar_output if jar_output == jar_input else jar_output.as_output())
|
||||
|
||||
cmd.add("-library")
|
||||
cmd.add(cmd_args(android_toolchain.android_bootclasspath, delimiter = get_path_separator()))
|
||||
|
||||
cmd.add("-printmapping", mapping.as_output())
|
||||
if configuration:
|
||||
cmd.add("-printconfiguration", configuration.as_output())
|
||||
if seeds:
|
||||
cmd.add("-printseeds", seeds.as_output())
|
||||
if usage:
|
||||
cmd.add("-printusage", usage.as_output())
|
||||
|
||||
return cmd
|
||||
|
||||
def run_proguard(
|
||||
ctx: "context",
|
||||
android_toolchain: "AndroidToolchainInfo",
|
||||
java_toolchain: "JavaToolchainInfo",
|
||||
command_line_args_file: "artifact",
|
||||
command_line_args: "cmd_args",
|
||||
mapping_file: "artifact"):
|
||||
run_proguard_cmd = cmd_args()
|
||||
run_proguard_cmd.add(
|
||||
java_toolchain.java[RunInfo],
|
||||
"-XX:-MaxFDLimit",
|
||||
ctx.attrs.proguard_jvm_args,
|
||||
"-Xmx{}".format(android_toolchain.proguard_max_heap_size),
|
||||
"-jar",
|
||||
android_toolchain.proguard_jar,
|
||||
)
|
||||
run_proguard_cmd.add(cmd_args(command_line_args_file, format = "@{}"))
|
||||
run_proguard_cmd.hidden(command_line_args)
|
||||
|
||||
# Some proguard configs can propagate the "-dontobfuscate" flag which disables
|
||||
# obfuscation and prevents the mapping.txt file from being generated.
|
||||
sh_cmd = cmd_args([
|
||||
"sh",
|
||||
"-c",
|
||||
"touch $1 && $2",
|
||||
"--",
|
||||
mapping_file.as_output(),
|
||||
cmd_args(run_proguard_cmd, delimiter = " "),
|
||||
])
|
||||
|
||||
ctx.actions.run(sh_cmd, category = "run_proguard")
|
||||
|
||||
# Note that ctx.attrs.skip_proguard means that we should create the proguard command line (since
|
||||
# e.g. Redex might want to consume it) but we don't actually run the proguard command.
|
||||
def get_proguard_output(
|
||||
ctx: "context",
|
||||
input_jars: {"artifact": "target_label"},
|
||||
java_packaging_deps: ["JavaPackagingDep"],
|
||||
aapt_generated_proguard_config: ["artifact", None]) -> ProguardOutput.type:
|
||||
proguard_configs = [packaging_dep.proguard_config for packaging_dep in java_packaging_deps if packaging_dep.proguard_config]
|
||||
if ctx.attrs.proguard_config:
|
||||
proguard_configs.append(ctx.attrs.proguard_config)
|
||||
if not ctx.attrs.ignore_aapt_proguard_config and aapt_generated_proguard_config:
|
||||
proguard_configs.append(aapt_generated_proguard_config)
|
||||
|
||||
if ctx.attrs.skip_proguard:
|
||||
inputs_to_unscrubbed_outputs = {input_jar: input_jar for input_jar in input_jars.keys()}
|
||||
mapping = ctx.actions.write("proguard/mapping.txt", [])
|
||||
configuration = None
|
||||
seeds = None
|
||||
usage = None
|
||||
else:
|
||||
inputs_to_unscrubbed_outputs = {input_jar: ctx.actions.declare_output(
|
||||
"proguard_output_jars/{}/{}_{}_obfuscated.jar".format(_UNSCRUBBED_JARS_DIR, input_jar.short_path, i),
|
||||
) for i, input_jar in enumerate(input_jars.keys())}
|
||||
mapping = ctx.actions.declare_output("proguard/mapping.txt")
|
||||
configuration = ctx.actions.declare_output("proguard/configuration.txt")
|
||||
seeds = ctx.actions.declare_output("proguard/seeds.txt")
|
||||
usage = ctx.actions.declare_output("proguard/usage.txt")
|
||||
|
||||
command_line_args = _get_proguard_command_line_args(
|
||||
ctx,
|
||||
inputs_to_unscrubbed_outputs,
|
||||
proguard_configs,
|
||||
mapping,
|
||||
configuration,
|
||||
seeds,
|
||||
usage,
|
||||
ctx.attrs._android_toolchain[AndroidToolchainInfo],
|
||||
)
|
||||
|
||||
command_line_args_file = ctx.actions.write("proguard/command-line.txt", command_line_args)
|
||||
|
||||
if ctx.attrs.skip_proguard:
|
||||
return ProguardOutput(
|
||||
jars_to_owners = input_jars,
|
||||
proguard_configuration_output_file = None,
|
||||
proguard_mapping_output_file = mapping,
|
||||
proguard_artifacts = [command_line_args_file, mapping],
|
||||
)
|
||||
else:
|
||||
unscrubbed_output_jars = {unscrubbed_output: input_jars[input_jar] for input_jar, unscrubbed_output in inputs_to_unscrubbed_outputs.items()}
|
||||
run_proguard(
|
||||
ctx,
|
||||
ctx.attrs._android_toolchain[AndroidToolchainInfo],
|
||||
ctx.attrs._java_toolchain[JavaToolchainInfo],
|
||||
command_line_args_file,
|
||||
command_line_args,
|
||||
mapping,
|
||||
)
|
||||
output_jars = {}
|
||||
for i, (unscrubbed_jar, target_label) in enumerate(unscrubbed_output_jars.items()):
|
||||
output = ctx.actions.declare_output(unscrubbed_jar.short_path.replace("{}/".format(_UNSCRUBBED_JARS_DIR), ""))
|
||||
ctx.actions.run(
|
||||
cmd_args([ctx.attrs._java_toolchain[JavaToolchainInfo].zip_scrubber, unscrubbed_jar, output.as_output()]),
|
||||
category = "scrub_jar",
|
||||
identifier = str(i),
|
||||
)
|
||||
output_jars[output] = target_label
|
||||
|
||||
return ProguardOutput(
|
||||
jars_to_owners = output_jars,
|
||||
proguard_configuration_output_file = configuration,
|
||||
proguard_mapping_output_file = mapping,
|
||||
proguard_artifacts = [command_line_args_file, mapping, configuration, seeds, usage],
|
||||
)
|
||||
229
vendor/cxx/tools/buck/prelude/android/r_dot_java.bzl
vendored
Normal file
229
vendor/cxx/tools/buck/prelude/android/r_dot_java.bzl
vendored
Normal file
|
|
@ -0,0 +1,229 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load("@prelude//java:java_library.bzl", "compile_to_jar")
|
||||
load("@prelude//java:java_providers.bzl", "JavaClasspathEntry", "JavaLibraryInfo", "derive_compiling_deps")
|
||||
|
||||
RDotJavaSourceCode = record(
|
||||
r_dot_java_source_code_dir = "artifact",
|
||||
r_dot_java_source_code_dir_listing = "artifact",
|
||||
strings_source_code_dir = ["artifact", None],
|
||||
strings_source_code_dir_listing = ["artifact", None],
|
||||
ids_source_code_dir = ["artifact", None],
|
||||
ids_source_code_dir_listing = ["artifact", None],
|
||||
)
|
||||
|
||||
def get_dummy_r_dot_java(
|
||||
ctx: "context",
|
||||
merge_android_resources_tool: RunInfo.type,
|
||||
java_toolchain: "JavaToolchainInfo",
|
||||
android_resources: ["AndroidResourceInfo"],
|
||||
union_package: [str.type, None]) -> "JavaLibraryInfo":
|
||||
r_dot_java_source_code = _generate_r_dot_java_source_code(ctx, merge_android_resources_tool, android_resources, "dummy_r_dot_java", union_package = union_package)
|
||||
library_output = _generate_and_compile_r_dot_java(
|
||||
ctx,
|
||||
r_dot_java_source_code.r_dot_java_source_code_dir,
|
||||
r_dot_java_source_code.r_dot_java_source_code_dir_listing,
|
||||
java_toolchain,
|
||||
"dummy_r_dot_java",
|
||||
)
|
||||
return JavaLibraryInfo(
|
||||
compiling_deps = derive_compiling_deps(ctx.actions, library_output, []),
|
||||
library_output = library_output,
|
||||
output_for_classpath_macro = library_output.full_library,
|
||||
)
|
||||
|
||||
def generate_r_dot_javas(
|
||||
ctx: "context",
|
||||
merge_android_resources_tool: RunInfo.type,
|
||||
java_toolchain: "JavaToolchainInfo",
|
||||
android_resources: ["AndroidResourceInfo"],
|
||||
banned_duplicate_resource_types: [str.type],
|
||||
uber_r_dot_txt_files: ["artifact"],
|
||||
override_symbols_paths: ["artifact"],
|
||||
duplicate_resources_allowlist: ["artifact", None],
|
||||
union_package: [str.type, None],
|
||||
referenced_resources_lists: ["artifact"]) -> ["JavaLibraryInfo"]:
|
||||
r_dot_java_source_code = _generate_r_dot_java_source_code(
|
||||
ctx,
|
||||
merge_android_resources_tool,
|
||||
android_resources,
|
||||
"r_dot_java",
|
||||
generate_strings_and_ids_separately = True,
|
||||
force_final_resources_ids = True,
|
||||
banned_duplicate_resource_types = banned_duplicate_resource_types,
|
||||
uber_r_dot_txt_files = uber_r_dot_txt_files,
|
||||
override_symbols_paths = override_symbols_paths,
|
||||
duplicate_resources_allowlist = duplicate_resources_allowlist,
|
||||
union_package = union_package,
|
||||
referenced_resources_lists = referenced_resources_lists,
|
||||
)
|
||||
|
||||
main_library_output = _generate_and_compile_r_dot_java(
|
||||
ctx,
|
||||
r_dot_java_source_code.r_dot_java_source_code_dir,
|
||||
r_dot_java_source_code.r_dot_java_source_code_dir_listing,
|
||||
java_toolchain,
|
||||
"main_r_dot_java",
|
||||
)
|
||||
strings_library_output = _generate_and_compile_r_dot_java(
|
||||
ctx,
|
||||
r_dot_java_source_code.strings_source_code_dir,
|
||||
r_dot_java_source_code.strings_source_code_dir_listing,
|
||||
java_toolchain,
|
||||
"strings_r_dot_java",
|
||||
remove_classes = [".R$"],
|
||||
)
|
||||
ids_library_output = _generate_and_compile_r_dot_java(
|
||||
ctx,
|
||||
r_dot_java_source_code.ids_source_code_dir,
|
||||
r_dot_java_source_code.ids_source_code_dir_listing,
|
||||
java_toolchain,
|
||||
"ids_r_dot_java",
|
||||
remove_classes = [".R$"],
|
||||
)
|
||||
|
||||
return [JavaLibraryInfo(
|
||||
compiling_deps = derive_compiling_deps(ctx.actions, library_output, []),
|
||||
library_output = library_output,
|
||||
output_for_classpath_macro = library_output.full_library,
|
||||
) for library_output in [main_library_output, strings_library_output, ids_library_output]]
|
||||
|
||||
def _generate_r_dot_java_source_code(
|
||||
ctx: "context",
|
||||
merge_android_resources_tool: RunInfo.type,
|
||||
android_resources: ["AndroidResourceInfo"],
|
||||
identifier: str.type,
|
||||
force_final_resources_ids = False,
|
||||
generate_strings_and_ids_separately = False,
|
||||
banned_duplicate_resource_types: [str.type] = [],
|
||||
uber_r_dot_txt_files: ["artifact"] = [],
|
||||
override_symbols_paths: ["artifact"] = [],
|
||||
duplicate_resources_allowlist: ["artifact", None] = None,
|
||||
union_package: [str.type, None] = None,
|
||||
referenced_resources_lists: ["artifact"] = []) -> RDotJavaSourceCode.type:
|
||||
merge_resources_cmd = cmd_args(merge_android_resources_tool)
|
||||
|
||||
r_dot_txt_info = cmd_args()
|
||||
for android_resource in android_resources:
|
||||
r_dot_txt_info.add(cmd_args([android_resource.text_symbols, android_resource.r_dot_java_package, "_"], delimiter = " ")) # pass target name
|
||||
|
||||
r_dot_txt_info_file = ctx.actions.write("r_dot_txt_info_file_for_{}.txt".format(identifier), r_dot_txt_info)
|
||||
merge_resources_cmd.add(["--symbol-file-info", r_dot_txt_info_file])
|
||||
merge_resources_cmd.hidden([android_resource.r_dot_java_package for android_resource in android_resources])
|
||||
merge_resources_cmd.hidden([android_resource.text_symbols for android_resource in android_resources])
|
||||
|
||||
output_dir = ctx.actions.declare_output("{}_source_code".format(identifier))
|
||||
merge_resources_cmd.add(["--output-dir", output_dir.as_output()])
|
||||
output_dir_listing = ctx.actions.declare_output("{}_source_code_listing".format(identifier))
|
||||
merge_resources_cmd.add(["--output-dir-listing", output_dir_listing.as_output()])
|
||||
|
||||
if generate_strings_and_ids_separately:
|
||||
strings_output_dir = ctx.actions.declare_output("strings_source_code")
|
||||
merge_resources_cmd.add(["--strings-output-dir", strings_output_dir.as_output()])
|
||||
strings_output_dir_listing = ctx.actions.declare_output("strings_source_code_listing")
|
||||
merge_resources_cmd.add(["--strings-output-dir-listing", strings_output_dir_listing.as_output()])
|
||||
ids_output_dir = ctx.actions.declare_output("ids_source_code")
|
||||
merge_resources_cmd.add(["--ids-output-dir", ids_output_dir.as_output()])
|
||||
ids_output_dir_listing = ctx.actions.declare_output("ids_source_code_listing")
|
||||
merge_resources_cmd.add(["--ids-output-dir-listing", ids_output_dir_listing.as_output()])
|
||||
else:
|
||||
strings_output_dir = None
|
||||
strings_output_dir_listing = None
|
||||
ids_output_dir = None
|
||||
ids_output_dir_listing = None
|
||||
|
||||
if force_final_resources_ids:
|
||||
merge_resources_cmd.add("--force-final-resource-ids")
|
||||
|
||||
if len(banned_duplicate_resource_types) > 0:
|
||||
banned_duplicate_resource_types_file = ctx.actions.write("banned_duplicate_resource_types_file", banned_duplicate_resource_types)
|
||||
merge_resources_cmd.add(["--banned-duplicate-resource-types", banned_duplicate_resource_types_file])
|
||||
|
||||
if len(uber_r_dot_txt_files) > 0:
|
||||
uber_r_dot_txt_files_list = ctx.actions.write("uber_r_dot_txt_files_list", uber_r_dot_txt_files)
|
||||
merge_resources_cmd.add(["--uber-r-dot-txt", uber_r_dot_txt_files_list])
|
||||
merge_resources_cmd.hidden(uber_r_dot_txt_files)
|
||||
|
||||
if len(override_symbols_paths) > 0:
|
||||
override_symbols_paths_list = ctx.actions.write("override_symbols_paths_list", override_symbols_paths)
|
||||
merge_resources_cmd.add(["--override-symbols", override_symbols_paths_list])
|
||||
merge_resources_cmd.hidden(override_symbols_paths)
|
||||
|
||||
if duplicate_resources_allowlist != None:
|
||||
merge_resources_cmd.add(["--duplicate-resource-allowlist-path", duplicate_resources_allowlist])
|
||||
|
||||
if union_package != None:
|
||||
merge_resources_cmd.add(["--union-package", union_package])
|
||||
|
||||
if referenced_resources_lists:
|
||||
referenced_resources_file = ctx.actions.write("referenced_resources_lists", referenced_resources_lists)
|
||||
merge_resources_cmd.add(["--referenced-resources-lists", referenced_resources_file])
|
||||
merge_resources_cmd.hidden(referenced_resources_lists)
|
||||
|
||||
ctx.actions.run(merge_resources_cmd, category = "r_dot_java_merge_resources", identifier = identifier)
|
||||
|
||||
return RDotJavaSourceCode(
|
||||
r_dot_java_source_code_dir = output_dir,
|
||||
r_dot_java_source_code_dir_listing = output_dir_listing,
|
||||
strings_source_code_dir = strings_output_dir,
|
||||
strings_source_code_dir_listing = strings_output_dir_listing,
|
||||
ids_source_code_dir = ids_output_dir,
|
||||
ids_source_code_dir_listing = ids_output_dir_listing,
|
||||
)
|
||||
|
||||
def _generate_and_compile_r_dot_java(
|
||||
ctx: "context",
|
||||
r_dot_java_source_code_dir: "artifact",
|
||||
r_dot_java_src_listing: "artifact",
|
||||
java_toolchain: "JavaToolchainInfo",
|
||||
identifier: str.type,
|
||||
remove_classes: [str.type] = []) -> JavaClasspathEntry.type:
|
||||
r_dot_java_out = ctx.actions.declare_output("{}.jar".format(identifier))
|
||||
|
||||
# @lint-ignore-every BUILDIFIERLINT
|
||||
def compile_r_dot_java_srcs(ctx, artifacts, outputs):
|
||||
src_listing_string = artifacts[r_dot_java_src_listing].read_string()
|
||||
src_listing = src_listing_string.split("\n")[:-1] if src_listing_string else []
|
||||
r_dot_java_srcs = []
|
||||
copied_root = ctx.actions.declare_output("copied_{}".format(identifier))
|
||||
for path in src_listing:
|
||||
r_dot_java_srcs.append(copied_root.project(path))
|
||||
|
||||
cmd = cmd_args([
|
||||
java_toolchain.src_dir_helper[RunInfo],
|
||||
"copy",
|
||||
"--src-dir",
|
||||
r_dot_java_source_code_dir,
|
||||
"--dest-dir",
|
||||
copied_root.as_output(),
|
||||
] + src_listing)
|
||||
ctx.actions.run(
|
||||
cmd,
|
||||
category = "copy_r_dot_java_sources",
|
||||
identifier = identifier,
|
||||
)
|
||||
|
||||
compile_to_jar(
|
||||
ctx,
|
||||
output = outputs[r_dot_java_out],
|
||||
actions_prefix = identifier,
|
||||
javac_tool = None,
|
||||
srcs = r_dot_java_srcs,
|
||||
remove_classes = remove_classes,
|
||||
)
|
||||
|
||||
# Extracting an abi is unnecessary as there's not really anything to strip.
|
||||
outputs = JavaClasspathEntry(
|
||||
full_library = r_dot_java_out,
|
||||
abi = r_dot_java_out,
|
||||
required_for_source_only_abi = False,
|
||||
)
|
||||
|
||||
todo_inputs = []
|
||||
ctx.actions.dynamic_output(dynamic = [r_dot_java_src_listing], inputs = todo_inputs, outputs = [r_dot_java_out], f = compile_r_dot_java_srcs)
|
||||
return outputs
|
||||
91
vendor/cxx/tools/buck/prelude/android/robolectric_test.bzl
vendored
Normal file
91
vendor/cxx/tools/buck/prelude/android/robolectric_test.bzl
vendored
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load("@prelude//android:android_binary_resources_rules.bzl", "get_android_binary_resources_info")
|
||||
load("@prelude//android:android_library.bzl", "build_android_library")
|
||||
load("@prelude//android:android_providers.bzl", "merge_android_packageable_info")
|
||||
load("@prelude//android:android_toolchain.bzl", "AndroidToolchainInfo")
|
||||
load("@prelude//java:java_test.bzl", "build_junit_test")
|
||||
load("@prelude//java:java_toolchain.bzl", "JavaToolchainInfo")
|
||||
load("@prelude//utils:utils.bzl", "expect")
|
||||
load("@prelude//test/inject_test_run_info.bzl", "inject_test_run_info")
|
||||
|
||||
def robolectric_test_impl(ctx: "context") -> ["provider"]:
|
||||
_verify_attributes(ctx)
|
||||
|
||||
extra_cmds = []
|
||||
|
||||
# Force robolectric to only use local dependency resolution.
|
||||
extra_cmds.append("-Drobolectric.offline=true")
|
||||
if ctx.attrs.robolectric_runtime_dependency:
|
||||
runtime_dependencies_dir = ctx.attrs.robolectric_runtime_dependency
|
||||
else:
|
||||
runtime_dependencies_dir = ctx.actions.symlinked_dir("runtime_dependencies", {
|
||||
runtime_dep.basename: runtime_dep
|
||||
for runtime_dep in ctx.attrs.robolectric_runtime_dependencies
|
||||
})
|
||||
|
||||
extra_cmds.append(cmd_args(runtime_dependencies_dir, format = "-Drobolectric.dependency.dir={}"))
|
||||
|
||||
all_packaging_deps = ctx.attrs.deps + (ctx.attrs.deps_query or []) + ctx.attrs.exported_deps + ctx.attrs.runtime_deps
|
||||
android_packageable_info = merge_android_packageable_info(ctx.label, ctx.actions, all_packaging_deps)
|
||||
resources_info = get_android_binary_resources_info(
|
||||
ctx,
|
||||
all_packaging_deps,
|
||||
android_packageable_info,
|
||||
java_packaging_deps = [], # Only used for third-party jar resources, which we don't care about here.
|
||||
use_proto_format = False,
|
||||
referenced_resources_lists = [],
|
||||
)
|
||||
|
||||
test_config_properties_file = ctx.actions.write(
|
||||
"test_config.properties",
|
||||
[
|
||||
cmd_args(["android_resource_apk", resources_info.primary_resources_apk], delimiter = "="),
|
||||
cmd_args(["android_merged_manifest", resources_info.manifest], delimiter = "="),
|
||||
],
|
||||
)
|
||||
|
||||
# Robolectric looks for a file named /com/android/tools/test_config.properties on the classpath
|
||||
test_config_symlinked_dir = ctx.actions.symlinked_dir("test_config_symlinked_dir", {"com/android/tools/test_config.properties": test_config_properties_file})
|
||||
test_config_properties_jar = ctx.actions.declare_output("test_config_properties.jar")
|
||||
jar_cmd = cmd_args([
|
||||
ctx.attrs._java_toolchain[JavaToolchainInfo].jar,
|
||||
"-cfM", # -c: create new archive, -f: specify the file name, -M: do not create a manifest
|
||||
test_config_properties_jar.as_output(),
|
||||
"-C",
|
||||
test_config_symlinked_dir,
|
||||
".",
|
||||
])
|
||||
ctx.actions.run(jar_cmd, category = "test_config_properties_jar_cmd")
|
||||
extra_cmds.append(cmd_args().hidden(resources_info.primary_resources_apk, resources_info.manifest))
|
||||
|
||||
extra_classpath_entries = [test_config_properties_jar] + ctx.attrs._android_toolchain[AndroidToolchainInfo].android_bootclasspath
|
||||
extra_classpath_entries.extend([r_dot_java.library_output.full_library for r_dot_java in resources_info.r_dot_javas if r_dot_java.library_output])
|
||||
|
||||
java_providers, _ = build_android_library(ctx)
|
||||
|
||||
external_runner_test_info = build_junit_test(
|
||||
ctx,
|
||||
java_providers.java_library_info,
|
||||
java_providers.java_packaging_info,
|
||||
extra_cmds = extra_cmds,
|
||||
extra_classpath_entries = extra_classpath_entries,
|
||||
)
|
||||
|
||||
return inject_test_run_info(ctx, external_runner_test_info) + [
|
||||
java_providers.java_library_info,
|
||||
java_providers.java_packaging_info,
|
||||
java_providers.template_placeholder_info,
|
||||
java_providers.default_info,
|
||||
]
|
||||
|
||||
def _verify_attributes(ctx: "context"):
|
||||
expect(
|
||||
bool(ctx.attrs.robolectric_runtime_dependencies) != (ctx.attrs.robolectric_runtime_dependency != None),
|
||||
"Exactly one of robolectric_runtime_dependencies and robolectric_runtime_dependency must be specified!",
|
||||
)
|
||||
240
vendor/cxx/tools/buck/prelude/android/voltron.bzl
vendored
Normal file
240
vendor/cxx/tools/buck/prelude/android/voltron.bzl
vendored
Normal file
|
|
@ -0,0 +1,240 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load("@prelude//android:android_providers.bzl", "AndroidPackageableInfo", "merge_android_packageable_info")
|
||||
load("@prelude//android:android_toolchain.bzl", "AndroidToolchainInfo")
|
||||
load("@prelude//java:java_providers.bzl", "get_all_java_packaging_deps")
|
||||
load("@prelude//linking:shared_libraries.bzl", "SharedLibraryInfo", "merge_shared_libraries", "traverse_shared_library_info")
|
||||
load("@prelude//utils:utils.bzl", "expect", "flatten")
|
||||
|
||||
# "Voltron" gives us the ability to split our Android APKs into different "modules". These
|
||||
# modules can then be downloaded on demand rather than shipped with the "main" APK.
|
||||
#
|
||||
# The module corresponding to the "main" APK is called the "root" module.
|
||||
#
|
||||
# Voltron support comes in two main parts:
|
||||
# (1) Constructing the Voltron module graph (assigning targets to each module). This is done
|
||||
# by constructing a "target graph" and then delegating to buck1 to produce the module graph.
|
||||
# (2) Using the Voltron module graph while building our APK.
|
||||
#
|
||||
# For (1), in order to calculate which targets belong to each module, we reconstruct a "target
|
||||
# graph" from "deps" information that is propagated up through AndroidPackageableInfo.
|
||||
# In buck1 we use the underlying "TargetGraph" object that is based on the raw target
|
||||
# definitions. This results in some slightly different behavior for `provided_deps` - in
|
||||
# buck2, we (correctly) ignore `provided_deps`, since they do not influence the packaging of
|
||||
# the APK, whereas in `buck1`, we treat `provided_deps` the same as `deps`.
|
||||
# In practice, this rarely affects the module assignments, but can mean that `buck2` will
|
||||
# put a target inside a module whereas `buck1` will put it into the main APK (since `buck1`
|
||||
# can find a path from an "always in main APK seed" to the target via some `provided_dep`,
|
||||
# whereas `buck2` does not).
|
||||
#
|
||||
# For (2), we package up secondary DEX files and native libs into `assets/module_name` (see
|
||||
# dex_rules.bzl and android_binary_native_rules.bzl for more information on how we do that).
|
||||
# It is worth noting that we still put all of the non-root modules into the final APK. If
|
||||
# the module should be downloaded on demand, then it is removed from the final APK in a
|
||||
# subsequent post-processing step.
|
||||
#
|
||||
# There is also an `android_app_modularity` rule that just prints out details of the Voltron
|
||||
# module graph and is used for any subsequent verification.
|
||||
def android_app_modularity_impl(ctx: "context") -> ["provider"]:
|
||||
all_deps = ctx.attrs.deps + flatten(ctx.attrs.application_module_configs.values())
|
||||
android_packageable_info = merge_android_packageable_info(ctx.label, ctx.actions, all_deps)
|
||||
|
||||
shared_library_info = merge_shared_libraries(
|
||||
ctx.actions,
|
||||
deps = filter(None, [x.get(SharedLibraryInfo) for x in all_deps]),
|
||||
)
|
||||
traversed_shared_library_info = traverse_shared_library_info(shared_library_info)
|
||||
|
||||
cmd, output = _get_base_cmd_and_output(
|
||||
ctx.actions,
|
||||
ctx.label,
|
||||
android_packageable_info,
|
||||
traversed_shared_library_info,
|
||||
ctx.attrs._android_toolchain[AndroidToolchainInfo],
|
||||
ctx.attrs.application_module_configs,
|
||||
ctx.attrs.application_module_dependencies,
|
||||
ctx.attrs.application_module_blacklist,
|
||||
)
|
||||
|
||||
if ctx.attrs.should_include_classes:
|
||||
no_dx_target_labels = [no_dx_target.label.raw_target() for no_dx_target in ctx.attrs.no_dx]
|
||||
java_packaging_deps = [packaging_dep for packaging_dep in get_all_java_packaging_deps(ctx, all_deps) if packaging_dep.dex and packaging_dep.dex.dex.owner.raw_target() not in no_dx_target_labels]
|
||||
targets_to_jars_args = [cmd_args([str(packaging_dep.label.raw_target()), packaging_dep.jar], delimiter = " ") for packaging_dep in java_packaging_deps]
|
||||
targets_to_jars = ctx.actions.write("targets_to_jars.txt", targets_to_jars_args)
|
||||
cmd.add([
|
||||
"--targets-to-jars",
|
||||
targets_to_jars,
|
||||
]).hidden(targets_to_jars_args)
|
||||
|
||||
if ctx.attrs.should_include_libraries:
|
||||
targets_to_so_names_args = [cmd_args([str(shared_lib.label.raw_target()), so_name, str(shared_lib.can_be_asset)], delimiter = " ") for so_name, shared_lib in traversed_shared_library_info.items()]
|
||||
targets_to_so_names = ctx.actions.write("targets_to_so_names.txt", targets_to_so_names_args)
|
||||
cmd.add([
|
||||
"--targets-to-so-names",
|
||||
targets_to_so_names,
|
||||
]).hidden(targets_to_so_names_args)
|
||||
|
||||
ctx.actions.run(cmd, category = "apk_module_graph")
|
||||
|
||||
return [DefaultInfo(default_outputs = [output])]
|
||||
|
||||
def get_target_to_module_mapping(ctx: "context", deps: ["dependency"]) -> ["artifact", None]:
|
||||
if not ctx.attrs.application_module_configs:
|
||||
return None
|
||||
|
||||
all_deps = deps + flatten(ctx.attrs.application_module_configs.values())
|
||||
android_packageable_info = merge_android_packageable_info(ctx.label, ctx.actions, all_deps)
|
||||
|
||||
shared_library_info = merge_shared_libraries(
|
||||
ctx.actions,
|
||||
deps = filter(None, [x.get(SharedLibraryInfo) for x in all_deps]),
|
||||
)
|
||||
traversed_shared_library_info = traverse_shared_library_info(shared_library_info)
|
||||
|
||||
cmd, output = _get_base_cmd_and_output(
|
||||
ctx.actions,
|
||||
ctx.label,
|
||||
android_packageable_info,
|
||||
traversed_shared_library_info,
|
||||
ctx.attrs._android_toolchain[AndroidToolchainInfo],
|
||||
ctx.attrs.application_module_configs,
|
||||
ctx.attrs.application_module_dependencies,
|
||||
ctx.attrs.application_module_blacklist,
|
||||
)
|
||||
|
||||
cmd.add("--output-module-info-and-target-to-module-only")
|
||||
|
||||
ctx.actions.run(cmd, category = "apk_module_graph")
|
||||
|
||||
return output
|
||||
|
||||
def _get_base_cmd_and_output(
|
||||
actions: "actions",
|
||||
label: "label",
|
||||
android_packageable_info: "AndroidPackageableInfo",
|
||||
traversed_shared_library_info: {str.type: "SharedLibrary"},
|
||||
android_toolchain: "AndroidToolchainInfo",
|
||||
application_module_configs: {str.type: ["dependency"]},
|
||||
application_module_dependencies: [{str.type: [str.type]}, None],
|
||||
application_module_blocklist: [[["dependency"]], None]) -> ("cmd_args", "artifact"):
|
||||
deps_infos = list(android_packageable_info.deps.traverse()) if android_packageable_info.deps else []
|
||||
deps_map = {deps_info.name: deps_info.deps for deps_info in deps_infos}
|
||||
|
||||
target_graph_file = actions.write_json("target_graph.json", deps_map)
|
||||
application_module_configs_map = {
|
||||
module_name: [seed.label.raw_target() for seed in seeds if seed.get(AndroidPackageableInfo)]
|
||||
for module_name, seeds in application_module_configs.items()
|
||||
}
|
||||
application_module_configs_file = actions.write_json("application_module_configs.json", application_module_configs_map)
|
||||
application_module_dependencies_file = actions.write_json("application_module_dependencies.json", application_module_dependencies or {})
|
||||
output = actions.declare_output("apk_module_metadata.txt")
|
||||
|
||||
cmd = cmd_args([
|
||||
android_toolchain.apk_module_graph[RunInfo],
|
||||
"--root-target",
|
||||
str(label.raw_target()),
|
||||
"--target-graph",
|
||||
target_graph_file,
|
||||
"--seed-config-map",
|
||||
application_module_configs_file,
|
||||
"--app-module-dependencies-map",
|
||||
application_module_dependencies_file,
|
||||
"--output",
|
||||
output.as_output(),
|
||||
])
|
||||
|
||||
# Anything that is used by a wrap script needs to go into the primary APK, as do all
|
||||
# of their deps.
|
||||
|
||||
used_by_wrap_script_libs = [str(shared_lib.label.raw_target()) for shared_lib in traversed_shared_library_info.values() if shared_lib.for_primary_apk]
|
||||
prebuilt_native_library_dirs = list(android_packageable_info.prebuilt_native_library_dirs.traverse()) if android_packageable_info.prebuilt_native_library_dirs else []
|
||||
prebuilt_native_library_targets_for_primary_apk = [str(native_lib_dir.raw_target) for native_lib_dir in prebuilt_native_library_dirs if native_lib_dir.for_primary_apk]
|
||||
if application_module_blocklist or used_by_wrap_script_libs or prebuilt_native_library_targets_for_primary_apk:
|
||||
all_blocklisted_deps = used_by_wrap_script_libs + prebuilt_native_library_targets_for_primary_apk
|
||||
if application_module_blocklist:
|
||||
all_blocklisted_deps.extend([str(blocklisted_dep.label.raw_target()) for blocklisted_dep in flatten(application_module_blocklist)])
|
||||
|
||||
application_module_blocklist_file = actions.write(
|
||||
"application_module_blocklist.txt",
|
||||
all_blocklisted_deps,
|
||||
)
|
||||
cmd.add([
|
||||
"--always-in-main-apk-seeds",
|
||||
application_module_blocklist_file,
|
||||
])
|
||||
|
||||
return cmd, output
|
||||
|
||||
ROOT_MODULE = "dex"
|
||||
|
||||
def is_root_module(module: str.type) -> bool.type:
|
||||
return module == ROOT_MODULE
|
||||
|
||||
def all_targets_in_root_module(_module: str.type) -> str.type:
|
||||
return ROOT_MODULE
|
||||
|
||||
APKModuleGraphInfo = record(
|
||||
target_to_module_mapping_function = "function",
|
||||
module_to_canary_class_name_function = "function",
|
||||
module_to_module_deps_function = "function",
|
||||
)
|
||||
|
||||
def get_root_module_only_apk_module_graph_info() -> APKModuleGraphInfo.type:
|
||||
def root_module_canary_class_name(module: str.type):
|
||||
expect(is_root_module(module))
|
||||
return "secondary"
|
||||
|
||||
def root_module_deps(module: str.type):
|
||||
expect(is_root_module(module))
|
||||
return []
|
||||
|
||||
return APKModuleGraphInfo(
|
||||
target_to_module_mapping_function = all_targets_in_root_module,
|
||||
module_to_canary_class_name_function = root_module_canary_class_name,
|
||||
module_to_module_deps_function = root_module_deps,
|
||||
)
|
||||
|
||||
def get_apk_module_graph_info(
|
||||
ctx: "context",
|
||||
apk_module_graph_file: "artifact",
|
||||
artifacts) -> APKModuleGraphInfo.type:
|
||||
apk_module_graph_lines = artifacts[apk_module_graph_file].read_string().split("\n")
|
||||
module_count = int(apk_module_graph_lines[0])
|
||||
module_infos = apk_module_graph_lines[1:module_count + 1]
|
||||
target_to_module_lines = apk_module_graph_lines[module_count + 1:-1]
|
||||
expect(apk_module_graph_lines[-1] == "", "Expect last line to be an empty string!")
|
||||
|
||||
module_to_canary_class_name_map = {}
|
||||
module_to_module_deps_map = {}
|
||||
for line in module_infos:
|
||||
line_data = line.split(" ")
|
||||
module_name = line_data[0]
|
||||
canary_class_name = line_data[1]
|
||||
module_deps = [module_dep for module_dep in line_data[2:] if module_dep]
|
||||
module_to_canary_class_name_map[module_name] = canary_class_name
|
||||
module_to_module_deps_map[module_name] = module_deps
|
||||
|
||||
target_to_module_mapping = {str(ctx.label.raw_target()): ROOT_MODULE}
|
||||
for line in target_to_module_lines:
|
||||
target, module = line.split(" ")
|
||||
target_to_module_mapping[target] = module
|
||||
|
||||
def target_to_module_mapping_function(raw_target: str.type) -> str.type:
|
||||
return target_to_module_mapping.get(raw_target)
|
||||
|
||||
def module_to_canary_class_name_function(voltron_module: str.type) -> str.type:
|
||||
return module_to_canary_class_name_map.get(voltron_module)
|
||||
|
||||
def module_to_module_deps_function(voltron_module: str.type) -> list.type:
|
||||
return module_to_module_deps_map.get(voltron_module)
|
||||
|
||||
return APKModuleGraphInfo(
|
||||
target_to_module_mapping_function = target_to_module_mapping_function,
|
||||
module_to_canary_class_name_function = module_to_canary_class_name_function,
|
||||
module_to_module_deps_function = module_to_module_deps_function,
|
||||
)
|
||||
108
vendor/cxx/tools/buck/prelude/apple/apple_asset_catalog.bzl
vendored
Normal file
108
vendor/cxx/tools/buck/prelude/apple/apple_asset_catalog.bzl
vendored
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load("@prelude//apple:apple_toolchain_types.bzl", "AppleToolchainInfo")
|
||||
load("@prelude//utils:utils.bzl", "flatten")
|
||||
load(":apple_asset_catalog_compilation_options.bzl", "AppleAssetCatalogsCompilationOptions", "get_apple_asset_catalogs_compilation_options") # @unused Used as a type
|
||||
load(":apple_asset_catalog_types.bzl", "AppleAssetCatalogResult", "AppleAssetCatalogSpec", "StringWithSourceTarget")
|
||||
load(":apple_bundle_utility.bzl", "get_bundle_min_target_version", "get_bundle_resource_processing_options")
|
||||
load(":apple_sdk.bzl", "get_apple_sdk_name")
|
||||
load(":apple_sdk_metadata.bzl", "get_apple_sdk_metadata_for_sdk_name")
|
||||
load(":resource_groups.bzl", "create_resource_graph")
|
||||
|
||||
def apple_asset_catalog_impl(ctx: "context") -> ["provider"]:
|
||||
spec = AppleAssetCatalogSpec(
|
||||
app_icon = StringWithSourceTarget(source = ctx.label, value = ctx.attrs.app_icon) if ctx.attrs.app_icon != None else None,
|
||||
dirs = ctx.attrs.dirs,
|
||||
launch_image = StringWithSourceTarget(source = ctx.label, value = ctx.attrs.launch_image) if ctx.attrs.launch_image != None else None,
|
||||
)
|
||||
graph = create_resource_graph(
|
||||
ctx = ctx,
|
||||
labels = ctx.attrs.labels,
|
||||
deps = [],
|
||||
exported_deps = [],
|
||||
asset_catalog_spec = spec,
|
||||
)
|
||||
return [DefaultInfo(default_outputs = []), graph]
|
||||
|
||||
def compile_apple_asset_catalog(ctx: "context", specs: [AppleAssetCatalogSpec.type]) -> [AppleAssetCatalogResult.type, None]:
|
||||
single_spec = _merge_asset_catalog_specs(ctx, specs)
|
||||
if len(single_spec.dirs) == 0:
|
||||
return None
|
||||
plist = ctx.actions.declare_output("AssetCatalog.plist")
|
||||
catalog = ctx.actions.declare_output("AssetCatalogCompiled")
|
||||
processing_options = get_bundle_resource_processing_options(ctx)
|
||||
compilation_options = get_apple_asset_catalogs_compilation_options(ctx)
|
||||
command = _get_actool_command(ctx, single_spec, catalog.as_output(), plist.as_output(), compilation_options)
|
||||
ctx.actions.run(command, prefer_local = processing_options.prefer_local, allow_cache_upload = processing_options.allow_cache_upload, category = "apple_asset_catalog")
|
||||
return AppleAssetCatalogResult(compiled_catalog = catalog, catalog_plist = plist)
|
||||
|
||||
def _merge_asset_catalog_specs(ctx: "context", xs: [AppleAssetCatalogSpec.type]) -> AppleAssetCatalogSpec.type:
|
||||
app_icon = _get_at_most_one_attribute(ctx, xs, "app_icon")
|
||||
launch_image = _get_at_most_one_attribute(ctx, xs, "launch_image")
|
||||
dirs = dedupe(flatten([x.dirs for x in xs]))
|
||||
return AppleAssetCatalogSpec(app_icon = app_icon, dirs = dirs, launch_image = launch_image)
|
||||
|
||||
def _get_at_most_one_attribute(ctx: "context", xs: ["_record"], attr_name: str.type) -> ["StringWithSourceTarget", None]:
|
||||
all_values = dedupe(filter(None, [getattr(x, attr_name) for x in xs]))
|
||||
if len(all_values) > 1:
|
||||
fail("At most one asset catalog in the dependencies of `{}` can have an `{}` attribute. At least 2 catalogs are providing it: `{}` and `{}`.".format(_get_target(ctx), attr_name, all_values[0].source, all_values[1].source))
|
||||
elif len(all_values) == 1:
|
||||
return all_values[0]
|
||||
else:
|
||||
return None
|
||||
|
||||
def _get_target(ctx: "context") -> str.type:
|
||||
return ctx.label.package + ":" + ctx.label.name
|
||||
|
||||
def _get_actool_command(ctx: "context", info: AppleAssetCatalogSpec.type, catalog_output: "output_artifact", plist_output: "output_artifact", compilation_options: AppleAssetCatalogsCompilationOptions.type) -> "cmd_args":
|
||||
external_name = get_apple_sdk_name(ctx)
|
||||
target_device = get_apple_sdk_metadata_for_sdk_name(external_name).target_device_flags
|
||||
|
||||
actool = ctx.attrs._apple_toolchain[AppleToolchainInfo].actool
|
||||
actool_command = cmd_args([
|
||||
actool,
|
||||
"--platform",
|
||||
external_name,
|
||||
"--minimum-deployment-target",
|
||||
get_bundle_min_target_version(ctx),
|
||||
"--compile",
|
||||
catalog_output,
|
||||
"--output-partial-info-plist",
|
||||
plist_output,
|
||||
] +
|
||||
target_device +
|
||||
(
|
||||
["--app-icon", info.app_icon.value] if info.app_icon else []
|
||||
) + (
|
||||
["--launch-image", info.launch_image.value] if info.launch_image else []
|
||||
) + (
|
||||
["--notices"] if compilation_options.enable_notices else []
|
||||
) + (
|
||||
["--warnings"] if compilation_options.enable_warnings else []
|
||||
) + (
|
||||
["--errors"] if compilation_options.enable_errors else []
|
||||
) + (
|
||||
["--compress-pngs"] if compilation_options.compress_pngs else []
|
||||
) +
|
||||
["--optimization", compilation_options.optimization] +
|
||||
["--output-format", compilation_options.output_format] +
|
||||
compilation_options.extra_flags +
|
||||
info.dirs)
|
||||
|
||||
# `actool` expects the output directory to be present.
|
||||
# Use the wrapper script to create the directory first and then actually call `actool`.
|
||||
wrapper_script, _ = ctx.actions.write(
|
||||
"actool_wrapper.sh",
|
||||
[
|
||||
cmd_args(catalog_output, format = "mkdir -p {}"),
|
||||
cmd_args(actool_command, delimiter = " "),
|
||||
],
|
||||
allow_args = True,
|
||||
)
|
||||
command = cmd_args(["/bin/sh", wrapper_script]).hidden([actool_command])
|
||||
return command
|
||||
29
vendor/cxx/tools/buck/prelude/apple/apple_asset_catalog_compilation_options.bzl
vendored
Normal file
29
vendor/cxx/tools/buck/prelude/apple/apple_asset_catalog_compilation_options.bzl
vendored
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
AppleAssetCatalogsCompilationOptions = record(
|
||||
enable_notices = field(bool.type),
|
||||
enable_warnings = field(bool.type),
|
||||
enable_errors = field(bool.type),
|
||||
compress_pngs = field(bool.type),
|
||||
optimization = field(str.type),
|
||||
output_format = field(str.type),
|
||||
extra_flags = field([str.type]),
|
||||
)
|
||||
|
||||
def get_apple_asset_catalogs_compilation_options(ctx: "context") -> AppleAssetCatalogsCompilationOptions.type:
|
||||
options = ctx.attrs.asset_catalogs_compilation_options
|
||||
|
||||
return AppleAssetCatalogsCompilationOptions(
|
||||
enable_notices = options.get("notices", True),
|
||||
enable_warnings = options.get("warnings", True),
|
||||
enable_errors = options.get("errors", True),
|
||||
compress_pngs = options.get("compress_pngs", True),
|
||||
optimization = options.get("optimization", "space"),
|
||||
output_format = options.get("output_format", "human-readable-text"),
|
||||
extra_flags = options.get("extra_flags", []),
|
||||
)
|
||||
30
vendor/cxx/tools/buck/prelude/apple/apple_asset_catalog_types.bzl
vendored
Normal file
30
vendor/cxx/tools/buck/prelude/apple/apple_asset_catalog_types.bzl
vendored
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
StringWithSourceTarget = record(
|
||||
# Target providing the string value
|
||||
source = field("label"),
|
||||
value = field("string"),
|
||||
)
|
||||
|
||||
AppleAssetCatalogSpec = record(
|
||||
# At most one per given `apple_bundle` (including all transitive catalog dependencies),
|
||||
# optional reference in a form of a name (extension omitted) of an .appiconset which
|
||||
# contains an image set representing an application icon.
|
||||
# This set should be contained in one of catalogs referenced by `dirs` attribute.
|
||||
app_icon = field([StringWithSourceTarget.type, None]),
|
||||
dirs = field(["artifact"]),
|
||||
# Same as `app_icon` but with an application launch image semantics.
|
||||
launch_image = field([StringWithSourceTarget.type, None]),
|
||||
)
|
||||
|
||||
AppleAssetCatalogResult = record(
|
||||
# Directory which contains compiled assets ready to be copied into application bundle
|
||||
compiled_catalog = field("artifact"),
|
||||
# .plist file to be merged into main application Info.plist file, containing information about compiled assets
|
||||
catalog_plist = field("artifact"),
|
||||
)
|
||||
88
vendor/cxx/tools/buck/prelude/apple/apple_binary.bzl
vendored
Normal file
88
vendor/cxx/tools/buck/prelude/apple/apple_binary.bzl
vendored
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load("@prelude//apple:apple_stripping.bzl", "apple_strip_args")
|
||||
load("@prelude//cxx:cxx.bzl", "get_srcs_with_flags")
|
||||
load("@prelude//cxx:cxx_executable.bzl", "cxx_executable")
|
||||
load("@prelude//cxx:cxx_library_utility.bzl", "cxx_attr_deps", "cxx_attr_exported_deps")
|
||||
load("@prelude//cxx:cxx_types.bzl", "CxxRuleConstructorParams")
|
||||
load(
|
||||
"@prelude//cxx:link_groups.bzl",
|
||||
"get_link_group_info",
|
||||
)
|
||||
load(
|
||||
"@prelude//cxx:preprocessor.bzl",
|
||||
"CPreprocessor",
|
||||
)
|
||||
load(":apple_bundle_types.bzl", "AppleMinDeploymentVersionInfo")
|
||||
load(":apple_code_signing_types.bzl", "AppleEntitlementsInfo")
|
||||
load(":apple_dsym.bzl", "AppleDebuggableInfo", "DEBUGINFO_SUBTARGET", "DSYM_SUBTARGET", "get_apple_dsym")
|
||||
load(":apple_frameworks.bzl", "get_framework_search_path_flags")
|
||||
load(":apple_link_postprocessor.bzl", "get_apple_link_postprocessor")
|
||||
load(":apple_target_sdk_version.bzl", "get_min_deployment_version_for_node", "get_min_deployment_version_target_linker_flags", "get_min_deployment_version_target_preprocessor_flags")
|
||||
load(":apple_utility.bzl", "get_apple_cxx_headers_layout")
|
||||
load(":resource_groups.bzl", "create_resource_graph")
|
||||
load(":xcode.bzl", "apple_populate_xcode_attributes")
|
||||
|
||||
def apple_binary_impl(ctx: "context") -> ["provider"]:
|
||||
extra_link_flags = get_min_deployment_version_target_linker_flags(ctx) + _entitlements_link_flags(ctx)
|
||||
framework_search_path_pre = CPreprocessor(
|
||||
args = [get_framework_search_path_flags(ctx)],
|
||||
)
|
||||
constructor_params = CxxRuleConstructorParams(
|
||||
rule_type = "apple_binary",
|
||||
headers_layout = get_apple_cxx_headers_layout(ctx),
|
||||
extra_exported_link_flags = extra_link_flags,
|
||||
srcs = get_srcs_with_flags(ctx),
|
||||
extra_preprocessors = get_min_deployment_version_target_preprocessor_flags(ctx) + [framework_search_path_pre],
|
||||
strip_executable = ctx.attrs.stripped,
|
||||
strip_args_factory = apple_strip_args,
|
||||
cxx_populate_xcode_attributes_func = apple_populate_xcode_attributes,
|
||||
link_postprocessor = get_apple_link_postprocessor(ctx),
|
||||
link_group_info = get_link_group_info(ctx),
|
||||
)
|
||||
(cxx_output, _comp_db_info, xcode_data_info) = cxx_executable(ctx, constructor_params)
|
||||
|
||||
dsym_artifact = get_apple_dsym(
|
||||
ctx = ctx,
|
||||
executable = cxx_output.binary,
|
||||
external_debug_info = cxx_output.external_debug_info,
|
||||
action_identifier = cxx_output.binary.short_path,
|
||||
)
|
||||
cxx_output.sub_targets[DSYM_SUBTARGET] = [DefaultInfo(default_outputs = [dsym_artifact])]
|
||||
|
||||
cxx_output.sub_targets[DEBUGINFO_SUBTARGET] = [DefaultInfo(other_outputs = cxx_output.external_debug_info)]
|
||||
|
||||
min_version = get_min_deployment_version_for_node(ctx)
|
||||
min_version_providers = [AppleMinDeploymentVersionInfo(version = min_version)] if min_version != None else []
|
||||
|
||||
resource_graph = create_resource_graph(
|
||||
ctx = ctx,
|
||||
labels = ctx.attrs.labels,
|
||||
deps = cxx_attr_deps(ctx),
|
||||
exported_deps = cxx_attr_exported_deps(ctx),
|
||||
)
|
||||
|
||||
return [
|
||||
DefaultInfo(default_outputs = [cxx_output.binary], sub_targets = cxx_output.sub_targets),
|
||||
RunInfo(args = cmd_args(cxx_output.binary).hidden(cxx_output.runtime_files)),
|
||||
AppleEntitlementsInfo(entitlements_file = ctx.attrs.entitlements_file),
|
||||
AppleDebuggableInfo(dsyms = [dsym_artifact], external_debug_info = cxx_output.external_debug_info),
|
||||
xcode_data_info,
|
||||
] + [resource_graph] + min_version_providers
|
||||
|
||||
def _entitlements_link_flags(ctx: "context") -> [""]:
|
||||
return [
|
||||
"-Xlinker",
|
||||
"-sectcreate",
|
||||
"-Xlinker",
|
||||
"__TEXT",
|
||||
"-Xlinker",
|
||||
"__entitlements",
|
||||
"-Xlinker",
|
||||
ctx.attrs.entitlements_file,
|
||||
] if ctx.attrs.entitlements_file else []
|
||||
181
vendor/cxx/tools/buck/prelude/apple/apple_bundle.bzl
vendored
Normal file
181
vendor/cxx/tools/buck/prelude/apple/apple_bundle.bzl
vendored
Normal file
|
|
@ -0,0 +1,181 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load("@prelude//apple:apple_toolchain_types.bzl", "AppleToolchainInfo")
|
||||
load(
|
||||
"@prelude//ide_integrations:xcode.bzl",
|
||||
"XCODE_DATA_SUB_TARGET",
|
||||
"generate_xcode_data",
|
||||
)
|
||||
load("@prelude//utils:utils.bzl", "expect", "flatten")
|
||||
load(":apple_bundle_destination.bzl", "AppleBundleDestination")
|
||||
load(":apple_bundle_part.bzl", "AppleBundlePart", "assemble_bundle", "bundle_output")
|
||||
load(":apple_bundle_resources.bzl", "get_apple_bundle_resource_part_list", "get_is_watch_bundle")
|
||||
load(":apple_bundle_types.bzl", "AppleBundleInfo", "AppleBundleResourceInfo")
|
||||
load(":apple_bundle_utility.bzl", "get_bundle_min_target_version", "get_product_name")
|
||||
load(":apple_dsym.bzl", "AppleDebuggableInfo", "DEBUGINFO_SUBTARGET", "DSYM_SUBTARGET")
|
||||
load(":apple_sdk.bzl", "get_apple_sdk_name")
|
||||
load(":xcode.bzl", "apple_xcode_data_add_xctoolchain")
|
||||
|
||||
INSTALL_DATA_SUB_TARGET = "install-data"
|
||||
_INSTALL_DATA_FILE_NAME = "install_apple_data.json"
|
||||
|
||||
_PLIST = "plist"
|
||||
|
||||
_XCTOOLCHAIN_SUB_TARGET = "xctoolchain"
|
||||
|
||||
AppleBundlePartListConstructorParams = record(
|
||||
# The binaries/executables, required to create a bundle
|
||||
binaries = field([AppleBundlePart.type]),
|
||||
)
|
||||
|
||||
AppleBundlePartListOutput = record(
|
||||
# The parts to be copied into an Apple bundle, *including* binaries
|
||||
parts = field([AppleBundlePart.type]),
|
||||
# Part that holds the info.plist
|
||||
info_plist_part = field(AppleBundlePart.type),
|
||||
)
|
||||
|
||||
AppleBundleBinaryOutput = record(
|
||||
binary = field("artifact"),
|
||||
# In the case of watchkit, the `ctx.attrs.binary`'s not set, and we need to create a stub binary.
|
||||
is_watchkit_stub_binary = field(bool.type, False),
|
||||
)
|
||||
|
||||
def _get_binary(ctx: "context") -> AppleBundleBinaryOutput.type:
|
||||
# No binary means we are building watchOS bundle. In v1 bundle binary is present, but its sources are empty.
|
||||
if ctx.attrs.binary == None:
|
||||
return AppleBundleBinaryOutput(
|
||||
binary = _get_watch_kit_stub_artifact(ctx),
|
||||
is_watchkit_stub_binary = True,
|
||||
)
|
||||
|
||||
binary_info = ctx.attrs.binary[DefaultInfo].default_outputs
|
||||
if len(binary_info) != 1:
|
||||
fail("Expected single output artifact. Make sure the implementation of rule from `binary` attribute is correct.")
|
||||
return AppleBundleBinaryOutput(binary = binary_info[0])
|
||||
|
||||
def _get_binary_bundle_parts(ctx: "context", binary_output: AppleBundleBinaryOutput.type) -> [AppleBundlePart.type]:
|
||||
result = []
|
||||
|
||||
if binary_output.is_watchkit_stub_binary:
|
||||
# If we're using a stub binary from watchkit, we also need to add extra part for stub.
|
||||
result.append(AppleBundlePart(source = binary_output.binary, destination = AppleBundleDestination("watchkitstub"), new_name = "WK"))
|
||||
result.append(AppleBundlePart(source = binary_output.binary, destination = AppleBundleDestination("executables"), new_name = get_product_name(ctx)))
|
||||
return result
|
||||
|
||||
def _get_watch_kit_stub_artifact(ctx: "context") -> "artifact":
|
||||
expect(ctx.attrs.binary == None, "Stub is useful only when binary is not set which means watchOS bundle is built.")
|
||||
stub_binary = ctx.attrs._apple_toolchain[AppleToolchainInfo].watch_kit_stub_binary
|
||||
if stub_binary == None:
|
||||
fail("Expected Watch Kit stub binary to be provided when bundle binary is not set.")
|
||||
return stub_binary
|
||||
|
||||
def _apple_bundle_run_validity_checks(ctx: "context"):
|
||||
if ctx.attrs.extension == None:
|
||||
fail("`extension` attribute is required")
|
||||
|
||||
def _get_debuggable_deps(ctx: "context") -> ["AppleDebuggableInfo"]:
|
||||
deps = ctx.attrs.deps
|
||||
|
||||
# No binary means we are building watchOS bundle. In v1 bundle binary is present, but its sources are empty.
|
||||
if ctx.attrs.binary:
|
||||
deps.append(ctx.attrs.binary)
|
||||
|
||||
return filter(
|
||||
None,
|
||||
[dep.get(AppleDebuggableInfo) for dep in deps],
|
||||
)
|
||||
|
||||
def get_apple_bundle_part_list(ctx: "context", params: AppleBundlePartListConstructorParams.type) -> AppleBundlePartListOutput.type:
|
||||
resource_part_list = None
|
||||
if hasattr(ctx.attrs, "_resource_bundle") and ctx.attrs._resource_bundle != None:
|
||||
resource_info = ctx.attrs._resource_bundle[AppleBundleResourceInfo]
|
||||
if resource_info != None:
|
||||
resource_part_list = resource_info.resource_output
|
||||
|
||||
if resource_part_list == None:
|
||||
resource_part_list = get_apple_bundle_resource_part_list(ctx)
|
||||
|
||||
return AppleBundlePartListOutput(
|
||||
parts = resource_part_list.resource_parts + params.binaries,
|
||||
info_plist_part = resource_part_list.info_plist_part,
|
||||
)
|
||||
|
||||
def apple_bundle_impl(ctx: "context") -> ["provider"]:
|
||||
_apple_bundle_run_validity_checks(ctx)
|
||||
|
||||
binary_outputs = _get_binary(ctx)
|
||||
apple_bundle_part_list_output = get_apple_bundle_part_list(ctx, AppleBundlePartListConstructorParams(binaries = _get_binary_bundle_parts(ctx, binary_outputs)))
|
||||
|
||||
sub_targets = {}
|
||||
|
||||
debuggable_deps = _get_debuggable_deps(ctx)
|
||||
|
||||
dsym_artifacts = flatten([info.dsyms for info in debuggable_deps])
|
||||
if dsym_artifacts:
|
||||
sub_targets[DSYM_SUBTARGET] = [DefaultInfo(default_outputs = dsym_artifacts)]
|
||||
|
||||
external_debug_info = flatten([info.external_debug_info for info in debuggable_deps])
|
||||
sub_targets[DEBUGINFO_SUBTARGET] = [DefaultInfo(other_outputs = external_debug_info)]
|
||||
|
||||
bundle = bundle_output(ctx)
|
||||
|
||||
assemble_bundle(ctx, bundle, apple_bundle_part_list_output.parts, apple_bundle_part_list_output.info_plist_part)
|
||||
|
||||
sub_targets[_PLIST] = [DefaultInfo(default_outputs = [apple_bundle_part_list_output.info_plist_part.source])]
|
||||
|
||||
sub_targets[_XCTOOLCHAIN_SUB_TARGET] = ctx.attrs._apple_xctoolchain.providers
|
||||
|
||||
# Define the xcode data sub target
|
||||
xcode_data_default_info, xcode_data_info = generate_xcode_data(ctx, "apple_bundle", bundle, _xcode_populate_attributes, processed_info_plist = apple_bundle_part_list_output.info_plist_part.source)
|
||||
sub_targets[XCODE_DATA_SUB_TARGET] = xcode_data_default_info
|
||||
install_data = generate_install_data(ctx)
|
||||
|
||||
return [
|
||||
DefaultInfo(default_outputs = [bundle], sub_targets = sub_targets),
|
||||
AppleBundleInfo(bundle = bundle, binary_name = get_product_name(ctx), is_watchos = get_is_watch_bundle(ctx)),
|
||||
AppleDebuggableInfo(dsyms = dsym_artifacts, external_debug_info = external_debug_info),
|
||||
InstallInfo(
|
||||
installer = ctx.attrs._apple_installer,
|
||||
files = {
|
||||
"app_bundle": bundle,
|
||||
"options": install_data,
|
||||
},
|
||||
),
|
||||
xcode_data_info,
|
||||
]
|
||||
|
||||
def _xcode_populate_attributes(ctx, processed_info_plist: "artifact") -> {str.type: ""}:
|
||||
data = {
|
||||
"deployment_version": get_bundle_min_target_version(ctx),
|
||||
"info_plist": ctx.attrs.info_plist,
|
||||
"processed_info_plist": processed_info_plist,
|
||||
"product_name": get_product_name(ctx),
|
||||
"sdk": get_apple_sdk_name(ctx),
|
||||
}
|
||||
|
||||
apple_xcode_data_add_xctoolchain(ctx, data)
|
||||
return data
|
||||
|
||||
def generate_install_data(
|
||||
ctx: "context",
|
||||
populate_rule_specific_attributes_func: ["function", None] = None,
|
||||
**kwargs) -> "artifact":
|
||||
data = {
|
||||
"fullyQualifiedName": ctx.label,
|
||||
## TODO(T110665037): populate full path similar to bundle_spec.json
|
||||
"info_plist": ctx.attrs.info_plist,
|
||||
"use_idb": "true",
|
||||
## TODO(T110665037): read from .buckconfig
|
||||
"xcode_developer_path": "/Applications/Xcode_13.4.0_fb.app/Contents/Developer",
|
||||
}
|
||||
|
||||
if populate_rule_specific_attributes_func:
|
||||
data.update(populate_rule_specific_attributes_func(ctx, **kwargs))
|
||||
|
||||
return ctx.actions.write_json(_INSTALL_DATA_FILE_NAME, data)
|
||||
20
vendor/cxx/tools/buck/prelude/apple/apple_bundle_config.bzl
vendored
Normal file
20
vendor/cxx/tools/buck/prelude/apple/apple_bundle_config.bzl
vendored
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
def _maybe_get_bool(config: str.type, default: [None, bool.type]) -> [None, bool.type]:
|
||||
result = read_config("apple", config, None)
|
||||
if result == None:
|
||||
return default
|
||||
return result.lower() == "true"
|
||||
|
||||
def apple_bundle_config() -> {str.type: ""}:
|
||||
return {
|
||||
"_codesign_type": read_config("apple", "codesign_type_override", None),
|
||||
"_compile_resources_locally_override": _maybe_get_bool("compile_resources_locally_override", None),
|
||||
"_incremental_bundling_enabled": _maybe_get_bool("incremental_bundling_enabled", True),
|
||||
"_profile_bundling_enabled": _maybe_get_bool("profile_bundling_enabled", False),
|
||||
}
|
||||
132
vendor/cxx/tools/buck/prelude/apple/apple_bundle_destination.bzl
vendored
Normal file
132
vendor/cxx/tools/buck/prelude/apple/apple_bundle_destination.bzl
vendored
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load("@prelude//:paths.bzl", "paths")
|
||||
|
||||
# Abstraction of a place in a resulting bundle where file or directory will be copied. Actual value
|
||||
# of path relative to bundle root depends on a platform. This class is an implementation detail and
|
||||
# is not exposed to user unlike `AppleResourceDestination`.
|
||||
# v1 code is `com/facebook/buck/apple/AppleBundleDestination.java`
|
||||
AppleBundleDestination = enum(
|
||||
"resources",
|
||||
"frameworks",
|
||||
"executables",
|
||||
"plugins",
|
||||
"xpcservices",
|
||||
"metadata",
|
||||
"watchapp",
|
||||
"headers",
|
||||
"modules",
|
||||
"quicklook",
|
||||
"watchkitstub",
|
||||
"bundleroot",
|
||||
"loginitems",
|
||||
)
|
||||
|
||||
AppleBundleDestinationPaths = record(
|
||||
resources = field(str.type, ""),
|
||||
frameworks = field(str.type, ""),
|
||||
executables = field(str.type, ""),
|
||||
plugins = field(str.type, ""),
|
||||
xpcservices = field(str.type, ""),
|
||||
metadata = field(str.type, ""),
|
||||
watchapp = field(str.type, ""),
|
||||
headers = field(str.type, ""),
|
||||
modules = field(str.type, ""),
|
||||
quicklook = field(str.type, ""),
|
||||
watchkitstub = field(str.type, ""),
|
||||
bundleroot = field(str.type, ""),
|
||||
loginitems = field(str.type, ""),
|
||||
)
|
||||
|
||||
_IOSBundleDestinationPaths = AppleBundleDestinationPaths(
|
||||
frameworks = "Frameworks",
|
||||
plugins = "PlugIns",
|
||||
xpcservices = "XPCServices",
|
||||
watchapp = "Watch",
|
||||
quicklook = "Library/QuickLook",
|
||||
watchkitstub = "_WatchKitStub",
|
||||
)
|
||||
|
||||
_IOSFrameworkBundleDestinationPaths = AppleBundleDestinationPaths(
|
||||
frameworks = "Frameworks",
|
||||
xpcservices = "XPCServices",
|
||||
headers = "Headers",
|
||||
modules = "Modules",
|
||||
)
|
||||
|
||||
macOS_content_path = "Contents"
|
||||
_MacOSBundleDestinationPaths = AppleBundleDestinationPaths(
|
||||
resources = paths.join(macOS_content_path, "Resources"),
|
||||
frameworks = paths.join(macOS_content_path, "Frameworks"),
|
||||
executables = paths.join(macOS_content_path, "MacOS"),
|
||||
plugins = paths.join(macOS_content_path, "PlugIns"),
|
||||
xpcservices = paths.join(macOS_content_path, "XPCServices"),
|
||||
metadata = macOS_content_path,
|
||||
watchapp = macOS_content_path,
|
||||
headers = macOS_content_path,
|
||||
modules = macOS_content_path,
|
||||
quicklook = paths.join(macOS_content_path, "Library/QuickLook"),
|
||||
watchkitstub = macOS_content_path,
|
||||
bundleroot = macOS_content_path,
|
||||
loginitems = paths.join(macOS_content_path, "Library/LoginItems"),
|
||||
)
|
||||
|
||||
_MacOSFrameworkBundleDestinationPaths = AppleBundleDestinationPaths(
|
||||
resources = "Resources",
|
||||
frameworks = "Frameworks",
|
||||
xpcservices = "XPCServices",
|
||||
metadata = "Resources",
|
||||
headers = "Headers",
|
||||
modules = "Modules",
|
||||
)
|
||||
|
||||
def _get_apple_bundle_destinations_for_sdk_name(name: str.type) -> AppleBundleDestinationPaths.type:
|
||||
if name == "macosx" or name == "maccatalyst":
|
||||
return _MacOSBundleDestinationPaths
|
||||
else:
|
||||
return _IOSBundleDestinationPaths
|
||||
|
||||
def _get_apple_framework_bundle_destinations_for_sdk_name(name: str.type) -> AppleBundleDestinationPaths.type:
|
||||
if name == "macosx" or name == "maccatalyst":
|
||||
return _MacOSFrameworkBundleDestinationPaths
|
||||
else:
|
||||
return _IOSFrameworkBundleDestinationPaths
|
||||
|
||||
def bundle_relative_path_for_destination(destination: AppleBundleDestination.type, sdk_name: str.type, extension: str.type) -> str.type:
|
||||
if extension == "framework":
|
||||
bundle_destinations = _get_apple_framework_bundle_destinations_for_sdk_name(sdk_name)
|
||||
else:
|
||||
bundle_destinations = _get_apple_bundle_destinations_for_sdk_name(sdk_name)
|
||||
|
||||
if destination.value == "resources":
|
||||
return bundle_destinations.resources
|
||||
elif destination.value == "frameworks":
|
||||
return bundle_destinations.frameworks
|
||||
elif destination.value == "executables":
|
||||
return bundle_destinations.executables
|
||||
elif destination.value == "plugins":
|
||||
return bundle_destinations.plugins
|
||||
elif destination.value == "xpcservices":
|
||||
return bundle_destinations.xpcservices
|
||||
elif destination.value == "metadata":
|
||||
return bundle_destinations.metadata
|
||||
elif destination.value == "watchapp":
|
||||
return bundle_destinations.watchapp
|
||||
elif destination.value == "headers":
|
||||
return bundle_destinations.headers
|
||||
elif destination.value == "modules":
|
||||
return bundle_destinations.modules
|
||||
elif destination.value == "quicklook":
|
||||
return bundle_destinations.quicklook
|
||||
elif destination.value == "watchkitstub":
|
||||
return bundle_destinations.watchkitstub
|
||||
elif destination.value == "bundleroot":
|
||||
return bundle_destinations.bundleroot
|
||||
elif destination.value == "loginitems":
|
||||
return bundle_destinations.loginitems
|
||||
fail("Unsupported Apple bundle destination {}".format(destination))
|
||||
90
vendor/cxx/tools/buck/prelude/apple/apple_bundle_macro_layer.bzl
vendored
Normal file
90
vendor/cxx/tools/buck/prelude/apple/apple_bundle_macro_layer.bzl
vendored
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load(":apple_bundle_config.bzl", "apple_bundle_config")
|
||||
load(":apple_info_plist_substitutions_parsing.bzl", "parse_codesign_entitlements")
|
||||
|
||||
_RESOURCE_BUNDLE_FIELDS = [
|
||||
"asset_catalogs_compilation_options",
|
||||
"binary",
|
||||
"default_target_platform",
|
||||
"deps",
|
||||
"extension",
|
||||
"ibtool_flags",
|
||||
"ibtool_module_flag",
|
||||
"info_plist",
|
||||
"info_plist_substitutions",
|
||||
"product_name",
|
||||
"resource_group",
|
||||
"resource_group_map",
|
||||
]
|
||||
|
||||
def apple_bundle_macro_impl(apple_bundle_rule = None, apple_resource_bundle_rule = None, **kwargs):
|
||||
info_plist_substitutions = kwargs.get("info_plist_substitutions")
|
||||
kwargs.update(apple_bundle_config())
|
||||
|
||||
resource_bundle_target_name = None
|
||||
|
||||
# The `apple_resource_bundle()` target will _always_ be Xcode-based, so resources can always be used
|
||||
# from there. `resources_toolchain_enabled` exists only as a killswitch (or for testing/debugging purposes).
|
||||
# By default, we consistently get all resources from `apple_resource_bundle()` target across all OSes and
|
||||
# toolchains.
|
||||
resources_toolchain_enabled = (read_config("apple", "resources_toolchain_enabled", "true").lower() == "true")
|
||||
if resources_toolchain_enabled:
|
||||
resource_bundle_name = kwargs["name"] + "__ResourceBundle_Private"
|
||||
resource_bundle_kwargs = {
|
||||
"_bundle_target_name": kwargs["name"],
|
||||
"_compile_resources_locally_override": kwargs["_compile_resources_locally_override"],
|
||||
}
|
||||
for field_name in _RESOURCE_BUNDLE_FIELDS:
|
||||
resource_bundle_kwargs[field_name] = kwargs.get(field_name)
|
||||
|
||||
# TODO(T125269558): Remove usage of apple_resource_bundle() once we have exec groups.
|
||||
apple_resource_bundle_rule(
|
||||
name = resource_bundle_name,
|
||||
**resource_bundle_kwargs
|
||||
)
|
||||
|
||||
resource_bundle_target_name = ":{}".format(resource_bundle_name)
|
||||
|
||||
# Splitting the resource compilation into another rule means we can have
|
||||
# different exec platforms for the resource compilation and for the rest
|
||||
# of the bundling process. This allows us to send resource compilations
|
||||
# directly to RE.
|
||||
#
|
||||
# +-------------------------------------------------+
|
||||
# | apple_bundle() |
|
||||
# | Exec Platform: macOS/Linux |
|
||||
# | +--------+ +--------+ +------------------+ |
|
||||
# +---+ binary +--+ deps +-+ _resource_bundle +---+
|
||||
# +--------+ +--------+ +------------------+
|
||||
# | | |
|
||||
# | | |
|
||||
# | | +---------------+
|
||||
# | | |
|
||||
# | | |
|
||||
# | | v
|
||||
# | | +---------------------------------+
|
||||
# | +-----+ | apple_resource_bundle() |
|
||||
# | | | Exec Platform: macOS-only |
|
||||
# | | | +--------+ +--------+ |
|
||||
# | | +-----+ binary +--+ deps +------+
|
||||
# | | +--------+ +--------+
|
||||
# | | | |
|
||||
# | | | |
|
||||
# | v | |
|
||||
# | +-------------------+ | |
|
||||
# | | Dependencies |<--------+-----------+
|
||||
# | +-------------------+ |
|
||||
# | +-------------------+ |
|
||||
# +------>| Binary |<--------+
|
||||
# +-------------------+
|
||||
apple_bundle_rule(
|
||||
_codesign_entitlements = parse_codesign_entitlements(info_plist_substitutions),
|
||||
_resource_bundle = resource_bundle_target_name,
|
||||
**kwargs
|
||||
)
|
||||
171
vendor/cxx/tools/buck/prelude/apple/apple_bundle_part.bzl
vendored
Normal file
171
vendor/cxx/tools/buck/prelude/apple/apple_bundle_part.bzl
vendored
Normal file
|
|
@ -0,0 +1,171 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load("@prelude//:paths.bzl", "paths")
|
||||
load(":apple_bundle_destination.bzl", "AppleBundleDestination", "bundle_relative_path_for_destination")
|
||||
load(":apple_bundle_utility.bzl", "get_extension_attr", "get_product_name")
|
||||
load(":apple_code_signing_types.bzl", "AppleEntitlementsInfo", "CodeSignType")
|
||||
load(":apple_sdk.bzl", "get_apple_sdk_name")
|
||||
load(":apple_sdk_metadata.bzl", "get_apple_sdk_metadata_for_sdk_name")
|
||||
load(":apple_toolchain_types.bzl", "AppleToolchainInfo", "AppleToolsInfo")
|
||||
|
||||
# Defines where and what should be copied into
|
||||
AppleBundlePart = record(
|
||||
# A file of directory which content should be copied
|
||||
source = field("artifact"),
|
||||
# Where the source should be copied, the actual destination directory
|
||||
# inside bundle depends on target platform
|
||||
destination = AppleBundleDestination.type,
|
||||
# New file name if it should be renamed before copying.
|
||||
# Empty string value is applicable only when `source` is a directory,
|
||||
# in such case only content of the directory will be copied, as opposed to the directory itself.
|
||||
# When value is `None`, directory or file will be copied as it is, without renaming.
|
||||
new_name = field([str.type, None], None),
|
||||
# Marks parts which should be code signed separately from the whole bundle.
|
||||
codesign_on_copy = field(bool.type, False),
|
||||
)
|
||||
|
||||
def bundle_output(ctx: "context") -> "artifact":
|
||||
bundle_dir_name = _get_bundle_dir_name(ctx)
|
||||
output = ctx.actions.declare_output(bundle_dir_name)
|
||||
return output
|
||||
|
||||
def assemble_bundle(ctx: "context", bundle: "artifact", parts: [AppleBundlePart.type], info_plist_part: [AppleBundlePart.type, None]) -> None:
|
||||
all_parts = parts + [info_plist_part] if info_plist_part else []
|
||||
spec_file = _bundle_spec_json(ctx, all_parts)
|
||||
|
||||
tools = ctx.attrs._apple_tools[AppleToolsInfo]
|
||||
tool = tools.assemble_bundle
|
||||
|
||||
codesign_args = []
|
||||
codesign_type = _detect_codesign_type(ctx)
|
||||
|
||||
if codesign_type.value in ["distribution", "adhoc"]:
|
||||
codesign_args = [
|
||||
"--codesign",
|
||||
"--codesign-tool",
|
||||
ctx.attrs._apple_toolchain[AppleToolchainInfo].codesign,
|
||||
]
|
||||
|
||||
external_name = get_apple_sdk_name(ctx)
|
||||
platform_args = ["--platform", external_name]
|
||||
codesign_args.extend(platform_args)
|
||||
|
||||
if codesign_type.value != "adhoc":
|
||||
provisioning_profiles = ctx.attrs._provisioning_profiles[DefaultInfo]
|
||||
provisioning_profiles_args = ["--profiles-dir"] + provisioning_profiles.default_outputs
|
||||
codesign_args.extend(provisioning_profiles_args)
|
||||
|
||||
# TODO(T116604880): use `apple.use_entitlements_when_adhoc_code_signing` buckconfig value
|
||||
maybe_entitlements = _entitlements_file(ctx)
|
||||
entitlements_args = ["--entitlements", maybe_entitlements] if maybe_entitlements else []
|
||||
codesign_args.extend(entitlements_args)
|
||||
|
||||
identities_command = ctx.attrs._apple_toolchain[AppleToolchainInfo].codesign_identities_command
|
||||
identities_command_args = ["--codesign-identities-command", cmd_args(identities_command)] if identities_command else []
|
||||
codesign_args.extend(identities_command_args)
|
||||
else:
|
||||
codesign_args.append("--ad-hoc")
|
||||
|
||||
info_plist_args = [
|
||||
"--info-plist-source",
|
||||
info_plist_part.source,
|
||||
"--info-plist-destination",
|
||||
_bundle_relative_destination_path(ctx, info_plist_part),
|
||||
] if info_plist_part else []
|
||||
codesign_args.extend(info_plist_args)
|
||||
elif codesign_type.value == "skip":
|
||||
pass
|
||||
else:
|
||||
fail("Code sign type `{}` not supported".format(codesign_type))
|
||||
|
||||
command = cmd_args([
|
||||
tool,
|
||||
"--output",
|
||||
bundle.as_output(),
|
||||
"--spec",
|
||||
spec_file,
|
||||
] + codesign_args)
|
||||
command.hidden([part.source for part in all_parts])
|
||||
run_incremental_args = {}
|
||||
incremental_state = ctx.actions.declare_output("incremental_state.json").as_output()
|
||||
|
||||
# Fallback to value from buckconfig
|
||||
incremental_bundling_enabled = ctx.attrs.incremental_bundling_enabled or ctx.attrs._incremental_bundling_enabled
|
||||
|
||||
if incremental_bundling_enabled:
|
||||
command.add("--incremental-state", incremental_state)
|
||||
run_incremental_args = {
|
||||
"metadata_env_var": "ACTION_METADATA",
|
||||
"metadata_path": "action_metadata.json",
|
||||
"no_outputs_cleanup": True,
|
||||
}
|
||||
category = "apple_assemble_bundle_incremental"
|
||||
else:
|
||||
# overwrite file with incremental state so if previous and next builds are incremental
|
||||
# (as opposed to the current non-incremental one), next one won't assume there is a
|
||||
# valid incremental state.
|
||||
command.hidden(ctx.actions.write_json(incremental_state, {}))
|
||||
category = "apple_assemble_bundle"
|
||||
|
||||
if ctx.attrs._profile_bundling_enabled:
|
||||
profile_output = ctx.actions.declare_output("bundling_profile.txt").as_output()
|
||||
command.add("--profile-output", profile_output)
|
||||
|
||||
force_local_bundling = codesign_type.value != "skip"
|
||||
ctx.actions.run(
|
||||
command,
|
||||
local_only = force_local_bundling,
|
||||
prefer_local = not force_local_bundling,
|
||||
category = category,
|
||||
**run_incremental_args
|
||||
)
|
||||
|
||||
def _get_bundle_dir_name(ctx: "context") -> str.type:
|
||||
return paths.replace_extension(get_product_name(ctx), "." + get_extension_attr(ctx))
|
||||
|
||||
def _bundle_relative_destination_path(ctx: "context", part: AppleBundlePart.type) -> str.type:
|
||||
bundle_relative_path = bundle_relative_path_for_destination(part.destination, get_apple_sdk_name(ctx), ctx.attrs.extension)
|
||||
destination_file_or_directory_name = part.new_name if part.new_name != None else paths.basename(part.source.short_path)
|
||||
return paths.join(bundle_relative_path, destination_file_or_directory_name)
|
||||
|
||||
# Returns JSON to be passed into bundle assembling tool. It should contain a dictionary which maps bundle relative destination paths to source paths."
|
||||
def _bundle_spec_json(ctx: "context", parts: [AppleBundlePart.type]) -> "artifact":
|
||||
specs = []
|
||||
|
||||
for part in parts:
|
||||
part_spec = {
|
||||
"dst": _bundle_relative_destination_path(ctx, part),
|
||||
"src": part.source,
|
||||
}
|
||||
if part.codesign_on_copy:
|
||||
part_spec["codesign_on_copy"] = True
|
||||
specs.append(part_spec)
|
||||
|
||||
return ctx.actions.write_json("bundle_spec.json", specs)
|
||||
|
||||
def _detect_codesign_type(ctx: "context") -> CodeSignType.type:
|
||||
if ctx.attrs.extension not in ["app", "appex"]:
|
||||
# Only code sign application bundles and extensions
|
||||
return CodeSignType("skip")
|
||||
|
||||
if ctx.attrs._codesign_type:
|
||||
return CodeSignType(ctx.attrs._codesign_type)
|
||||
sdk_name = get_apple_sdk_name(ctx)
|
||||
is_ad_hoc_sufficient = get_apple_sdk_metadata_for_sdk_name(sdk_name).is_ad_hoc_code_sign_sufficient
|
||||
return CodeSignType("adhoc" if is_ad_hoc_sufficient else "distribution")
|
||||
|
||||
def _entitlements_file(ctx: "context") -> ["artifact", None]:
|
||||
if not ctx.attrs.binary:
|
||||
return None
|
||||
|
||||
# The `binary` attribute can be either an apple_binary or a dynamic library from apple_library
|
||||
binary_entitlement_info = ctx.attrs.binary[AppleEntitlementsInfo]
|
||||
if binary_entitlement_info and binary_entitlement_info.entitlements_file:
|
||||
return binary_entitlement_info.entitlements_file
|
||||
|
||||
return ctx.attrs._codesign_entitlements
|
||||
344
vendor/cxx/tools/buck/prelude/apple/apple_bundle_resources.bzl
vendored
Normal file
344
vendor/cxx/tools/buck/prelude/apple/apple_bundle_resources.bzl
vendored
Normal file
|
|
@ -0,0 +1,344 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load("@prelude//:paths.bzl", "paths")
|
||||
load("@prelude//:resources.bzl", "gather_resources")
|
||||
load("@prelude//apple:apple_toolchain_types.bzl", "AppleToolchainInfo")
|
||||
load("@prelude//utils:utils.bzl", "expect", "flatten_dict")
|
||||
load(
|
||||
":apple_asset_catalog.bzl",
|
||||
"compile_apple_asset_catalog",
|
||||
)
|
||||
load(
|
||||
":apple_asset_catalog_types.bzl",
|
||||
"AppleAssetCatalogSpec", # @unused Used as a type
|
||||
)
|
||||
load(":apple_bundle_destination.bzl", "AppleBundleDestination")
|
||||
load(":apple_bundle_part.bzl", "AppleBundlePart")
|
||||
load(":apple_bundle_types.bzl", "AppleBundleInfo")
|
||||
load(":apple_bundle_utility.bzl", "get_bundle_resource_processing_options", "get_extension_attr", "get_product_name")
|
||||
load(":apple_core_data.bzl", "compile_apple_core_data")
|
||||
load(
|
||||
":apple_core_data_types.bzl",
|
||||
"AppleCoreDataSpec", # @unused Used as a type
|
||||
)
|
||||
load(":apple_info_plist.bzl", "process_info_plist", "process_plist")
|
||||
load(
|
||||
":apple_resource_types.bzl",
|
||||
"AppleResourceDestination",
|
||||
"AppleResourceSpec", # @unused Used as a type
|
||||
)
|
||||
load(":apple_resource_utility.bzl", "apple_bundle_destination_from_resource_destination")
|
||||
load(
|
||||
":resource_groups.bzl",
|
||||
"create_resource_graph",
|
||||
"get_filtered_resources",
|
||||
"get_resource_graph_node_map_func",
|
||||
"get_resource_group_info",
|
||||
)
|
||||
|
||||
AppleBundleResourcePartListOutput = record(
|
||||
# Resource parts to be copied into an Apple bundle, *excluding* binaries
|
||||
resource_parts = field([AppleBundlePart.type]),
|
||||
# Part that holds the info.plist
|
||||
info_plist_part = field(AppleBundlePart.type),
|
||||
)
|
||||
|
||||
def get_apple_bundle_resource_part_list(ctx: "context") -> AppleBundleResourcePartListOutput.type:
|
||||
parts = []
|
||||
|
||||
parts.extend(_create_pkg_info_if_needed(ctx))
|
||||
|
||||
(resource_specs, asset_catalog_specs, core_data_specs) = _select_resources(ctx)
|
||||
|
||||
# If we've pulled in native/C++ resources from deps, inline them into the
|
||||
# bundle under the `CxxResources` namespace.
|
||||
cxx_resources = flatten_dict(gather_resources(
|
||||
label = ctx.label,
|
||||
deps = ctx.attrs.deps,
|
||||
).values())
|
||||
if cxx_resources:
|
||||
cxx_res_dir = ctx.actions.copied_dir(
|
||||
"CxxResources",
|
||||
{
|
||||
name: resource
|
||||
for name, (resource, _) in cxx_resources.items()
|
||||
},
|
||||
)
|
||||
resource_specs.append(
|
||||
AppleResourceSpec(
|
||||
dirs = [cxx_res_dir],
|
||||
destination = AppleResourceDestination("resources"),
|
||||
),
|
||||
)
|
||||
|
||||
asset_catalog_result = compile_apple_asset_catalog(ctx, asset_catalog_specs)
|
||||
if asset_catalog_result != None:
|
||||
asset_catalog_part = AppleBundlePart(
|
||||
source = asset_catalog_result.compiled_catalog,
|
||||
destination = AppleBundleDestination("resources"),
|
||||
# We only interested in directory contents
|
||||
new_name = "",
|
||||
)
|
||||
parts.append(asset_catalog_part)
|
||||
|
||||
extra_plist = asset_catalog_result.catalog_plist if asset_catalog_result != None else None
|
||||
info_plist_part = process_info_plist(ctx = ctx, override_input = extra_plist)
|
||||
|
||||
core_data_result = compile_apple_core_data(ctx, core_data_specs, get_product_name(ctx))
|
||||
if core_data_result != None:
|
||||
core_data_part = AppleBundlePart(
|
||||
source = core_data_result,
|
||||
destination = AppleBundleDestination("resources"),
|
||||
# We only interested in directory contents
|
||||
new_name = "",
|
||||
)
|
||||
parts.append(core_data_part)
|
||||
|
||||
parts.extend(_copy_resources(ctx, resource_specs))
|
||||
parts.extend(_copy_first_level_bundles(ctx))
|
||||
|
||||
return AppleBundleResourcePartListOutput(
|
||||
resource_parts = parts,
|
||||
info_plist_part = info_plist_part,
|
||||
)
|
||||
|
||||
# Same logic as in v1, see `buck_client/src/com/facebook/buck/apple/ApplePkgInfo.java`
|
||||
def _create_pkg_info_if_needed(ctx: "context") -> [AppleBundlePart.type]:
|
||||
extension = get_extension_attr(ctx)
|
||||
if extension == "xpc" or extension == "qlgenerator":
|
||||
return []
|
||||
artifact = ctx.actions.write("PkgInfo", "APPLWRUN\n")
|
||||
return [AppleBundlePart(source = artifact, destination = AppleBundleDestination("metadata"))]
|
||||
|
||||
def _select_resources(ctx: "context") -> (([AppleResourceSpec.type], [AppleAssetCatalogSpec.type], [AppleCoreDataSpec.type])):
|
||||
resource_group_info = get_resource_group_info(ctx)
|
||||
if resource_group_info:
|
||||
resource_groups_deps = [mapping.root.node for group in resource_group_info.groups for mapping in group.mappings if mapping.root != None]
|
||||
resource_group_mappings = resource_group_info.mappings
|
||||
else:
|
||||
resource_groups_deps = []
|
||||
resource_group_mappings = {}
|
||||
deps = ctx.attrs.deps + filter(None, [ctx.attrs.binary])
|
||||
resource_graph = create_resource_graph(
|
||||
ctx = ctx,
|
||||
labels = [],
|
||||
deps = deps + resource_groups_deps,
|
||||
exported_deps = [],
|
||||
)
|
||||
resource_graph_node_map_func = get_resource_graph_node_map_func(resource_graph)
|
||||
return get_filtered_resources(ctx.label, resource_graph_node_map_func, ctx.attrs.resource_group, resource_group_mappings)
|
||||
|
||||
def _copy_resources(ctx: "context", specs: [AppleResourceSpec.type]) -> [AppleBundlePart.type]:
|
||||
result = []
|
||||
|
||||
for spec in specs:
|
||||
bundle_destination = apple_bundle_destination_from_resource_destination(spec.destination)
|
||||
result += [_process_apple_resource_file_if_needed(
|
||||
ctx = ctx,
|
||||
file = x,
|
||||
destination = bundle_destination,
|
||||
destination_relative_path = None,
|
||||
codesign_on_copy = spec.codesign_files_on_copy,
|
||||
) for x in spec.files]
|
||||
result += _bundle_parts_for_dirs(spec.dirs, bundle_destination, False)
|
||||
result += _bundle_parts_for_dirs(spec.content_dirs, bundle_destination, True)
|
||||
result += _bundle_parts_for_variant_files(ctx, spec)
|
||||
|
||||
return result
|
||||
|
||||
def _copy_first_level_bundles(ctx: "context") -> [AppleBundlePart.type]:
|
||||
first_level_bundle_infos = filter(None, [dep.get(AppleBundleInfo) for dep in ctx.attrs.deps])
|
||||
return filter(None, [_copied_bundle_spec(info) for info in first_level_bundle_infos])
|
||||
|
||||
def _copied_bundle_spec(bundle_info: AppleBundleInfo.type) -> [None, AppleBundlePart.type]:
|
||||
bundle = bundle_info.bundle
|
||||
bundle_extension = paths.split_extension(bundle.short_path)[1]
|
||||
if bundle_extension == ".framework":
|
||||
destination = AppleBundleDestination("frameworks")
|
||||
codesign_on_copy = True
|
||||
elif bundle_extension == ".app":
|
||||
expect(bundle_info.is_watchos != None, "Field should be set for bundles with extension {}".format(bundle_extension))
|
||||
destination = AppleBundleDestination("watchapp" if bundle_info.is_watchos else "plugins")
|
||||
codesign_on_copy = False
|
||||
elif bundle_extension == ".appex":
|
||||
destination = AppleBundleDestination("plugins")
|
||||
codesign_on_copy = False
|
||||
else:
|
||||
fail("Extension `{}` is not yet supported.".format(bundle_extension))
|
||||
return AppleBundlePart(
|
||||
source = bundle,
|
||||
destination = destination,
|
||||
codesign_on_copy = codesign_on_copy,
|
||||
)
|
||||
|
||||
def _bundle_parts_for_dirs(generated_dirs: ["artifact"], destination: AppleBundleDestination.type, copy_contents_only: bool.type) -> [AppleBundlePart.type]:
|
||||
return [AppleBundlePart(
|
||||
source = generated_dir,
|
||||
destination = destination,
|
||||
new_name = "" if copy_contents_only else None,
|
||||
) for generated_dir in generated_dirs]
|
||||
|
||||
def _bundle_parts_for_variant_files(ctx: "context", spec: AppleResourceSpec.type) -> [AppleBundlePart.type]:
|
||||
result = []
|
||||
|
||||
# By definition, all variant files go into the resources destination
|
||||
bundle_destination = AppleBundleDestination("resources")
|
||||
for variant_file in spec.variant_files:
|
||||
variant_dest_subpath = _get_dest_subpath_for_variant_file(variant_file)
|
||||
bundle_part = _process_apple_resource_file_if_needed(
|
||||
ctx = ctx,
|
||||
file = variant_file,
|
||||
destination = bundle_destination,
|
||||
destination_relative_path = variant_dest_subpath,
|
||||
)
|
||||
result.append(bundle_part)
|
||||
|
||||
for locale, variant_files in spec.named_variant_files.items():
|
||||
if not locale.endswith(".lproj"):
|
||||
fail("Keys for named variant files have to end with '.lproj' suffix, got {}".format(locale))
|
||||
result += [
|
||||
_process_apple_resource_file_if_needed(
|
||||
ctx = ctx,
|
||||
file = variant_file,
|
||||
destination = bundle_destination,
|
||||
destination_relative_path = paths.join(locale, paths.basename(variant_file.short_path)),
|
||||
)
|
||||
for variant_file in variant_files
|
||||
]
|
||||
|
||||
return result
|
||||
|
||||
def _run_ibtool(
|
||||
ctx: "context",
|
||||
raw_file: "artifact",
|
||||
output: "output_artifact",
|
||||
action_flags: [str.type],
|
||||
target_device: [None, str.type],
|
||||
action_identifier: str.type,
|
||||
output_is_dir: bool.type) -> None:
|
||||
# TODO(T110378103): detect and add minimum deployment target automatically
|
||||
# TODO(T110378113): add support for ibtool modules (turned on by `ibtool_module_flag` field of `apple_bundle` rule)
|
||||
|
||||
# Equivalent of `AppleProcessResources::BASE_IBTOOL_FLAGS` from v1
|
||||
base_flags = ["--output-format", "human-readable-text", "--notices", "--warnings", "--errors"]
|
||||
|
||||
ibtool = ctx.attrs._apple_toolchain[AppleToolchainInfo].ibtool
|
||||
ibtool_command = [ibtool] + base_flags + (ctx.attrs.ibtool_flags or [])
|
||||
if target_device != None:
|
||||
ibtool_command.extend(["--target-device", target_device])
|
||||
ibtool_command.extend(action_flags)
|
||||
if output_is_dir:
|
||||
ibtool_command.append('"$TMPDIR"')
|
||||
else:
|
||||
ibtool_command.append(output)
|
||||
ibtool_command.append(raw_file)
|
||||
|
||||
if output_is_dir:
|
||||
# Sandboxing and fs isolation on RE machines results in Xcode tools failing
|
||||
# when those are working in freshly created directories in buck-out.
|
||||
# See https://fb.workplace.com/groups/1042353022615812/permalink/1872164996301273/
|
||||
# As a workaround create a directory in tmp, use it for Xcode tools, then
|
||||
# copy the result to buck-out.
|
||||
wrapper_script, _ = ctx.actions.write(
|
||||
"ibtool_wrapper.sh",
|
||||
[
|
||||
cmd_args('export TMPDIR="$(mktemp -d)"'),
|
||||
cmd_args(cmd_args(ibtool_command), delimiter = " "),
|
||||
cmd_args(output, format = 'mkdir -p {} && cp -r "$TMPDIR"/ {}'),
|
||||
],
|
||||
allow_args = True,
|
||||
)
|
||||
command = cmd_args(["/bin/sh", wrapper_script]).hidden([ibtool_command, output])
|
||||
else:
|
||||
command = ibtool_command
|
||||
|
||||
processing_options = get_bundle_resource_processing_options(ctx)
|
||||
ctx.actions.run(command, prefer_local = processing_options.prefer_local, allow_cache_upload = processing_options.allow_cache_upload, category = "apple_ibtool", identifier = action_identifier)
|
||||
|
||||
def _compile_ui_resource(
|
||||
ctx: "context",
|
||||
raw_file: "artifact",
|
||||
output: "output_artifact",
|
||||
target_device: [None, str.type] = None,
|
||||
output_is_dir: bool.type = False) -> None:
|
||||
_run_ibtool(
|
||||
ctx = ctx,
|
||||
raw_file = raw_file,
|
||||
output = output,
|
||||
action_flags = ["--compile"],
|
||||
target_device = target_device,
|
||||
action_identifier = "compile_" + raw_file.basename,
|
||||
output_is_dir = output_is_dir,
|
||||
)
|
||||
|
||||
def _link_ui_resource(
|
||||
ctx: "context",
|
||||
raw_file: "artifact",
|
||||
output: "output_artifact",
|
||||
target_device: [None, str.type] = None,
|
||||
output_is_dir: bool.type = False) -> None:
|
||||
_run_ibtool(
|
||||
ctx = ctx,
|
||||
raw_file = raw_file,
|
||||
output = output,
|
||||
action_flags = ["--link"],
|
||||
target_device = target_device,
|
||||
action_identifier = "link_" + raw_file.basename,
|
||||
output_is_dir = output_is_dir,
|
||||
)
|
||||
|
||||
def _process_apple_resource_file_if_needed(
|
||||
ctx: "context",
|
||||
file: "artifact",
|
||||
destination: AppleBundleDestination.type,
|
||||
destination_relative_path: [str.type, None],
|
||||
codesign_on_copy: bool.type = False) -> AppleBundlePart.type:
|
||||
output_dir = "_ProcessedResources"
|
||||
basename = paths.basename(file.short_path)
|
||||
output_is_contents_dir = False
|
||||
if basename.endswith(".plist") or basename.endswith(".stringsdict"):
|
||||
processed = ctx.actions.declare_output(paths.join(output_dir, file.short_path))
|
||||
process_plist(
|
||||
ctx = ctx,
|
||||
input = file,
|
||||
output = processed.as_output(),
|
||||
action_id = destination_relative_path,
|
||||
)
|
||||
elif basename.endswith(".storyboard"):
|
||||
compiled = ctx.actions.declare_output(paths.join(output_dir, paths.replace_extension(file.short_path, ".storyboardc")))
|
||||
if get_is_watch_bundle(ctx):
|
||||
output_is_contents_dir = True
|
||||
_compile_ui_resource(ctx = ctx, raw_file = file, output = compiled.as_output(), target_device = "watch")
|
||||
processed = ctx.actions.declare_output(paths.join(output_dir, paths.replace_extension(file.short_path, "_linked_storyboard")))
|
||||
_link_ui_resource(ctx = ctx, raw_file = compiled, output = processed.as_output(), target_device = "watch", output_is_dir = True)
|
||||
else:
|
||||
processed = compiled
|
||||
_compile_ui_resource(ctx, file, processed.as_output())
|
||||
elif basename.endswith(".xib"):
|
||||
processed = ctx.actions.declare_output(paths.join(output_dir, paths.replace_extension(file.short_path, ".nib")))
|
||||
_compile_ui_resource(ctx, file, processed.as_output())
|
||||
else:
|
||||
processed = file
|
||||
|
||||
# When name is empty string only content of the directory will be copied, as opposed to the directory itself.
|
||||
# When name is `None`, directory or file will be copied as it is, without renaming.
|
||||
new_name = destination_relative_path if destination_relative_path else ("" if output_is_contents_dir else None)
|
||||
return AppleBundlePart(source = processed, destination = destination, new_name = new_name, codesign_on_copy = codesign_on_copy)
|
||||
|
||||
# Returns a path relative to the _parent_ of the lproj dir.
|
||||
# For example, given a variant file with a short path of`XX/YY.lproj/ZZ`
|
||||
# it would return `YY.lproj/ZZ`.
|
||||
def _get_dest_subpath_for_variant_file(variant_file: "artifact") -> str.type:
|
||||
dir_name = paths.basename(paths.dirname(variant_file.short_path))
|
||||
if not dir_name.endswith("lproj"):
|
||||
fail("Variant files have to be in a directory with name ending in '.lproj' but `{}` was not.".format(variant_file.short_path))
|
||||
file_name = paths.basename(variant_file.short_path)
|
||||
return paths.join(dir_name, file_name)
|
||||
|
||||
def get_is_watch_bundle(ctx: "context") -> bool.type:
|
||||
return ctx.attrs._apple_toolchain[AppleToolchainInfo].watch_kit_stub_binary != None
|
||||
31
vendor/cxx/tools/buck/prelude/apple/apple_bundle_types.bzl
vendored
Normal file
31
vendor/cxx/tools/buck/prelude/apple/apple_bundle_types.bzl
vendored
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
# Provider flagging that result of the rule contains Apple bundle.
|
||||
# It might be copied into main bundle to appropriate place if rule
|
||||
# with this provider is a dependency of `apple_bundle`.
|
||||
AppleBundleInfo = provider(fields = [
|
||||
# Result bundle; `artifact`
|
||||
"bundle",
|
||||
# The name of the executable within the bundle.
|
||||
# `str.type`
|
||||
"binary_name",
|
||||
# If the bundle was built for watchOS Apple platform, this affects packaging.
|
||||
# Might be omitted for certain types of bundle (e.g. frameworks) when packaging doesn't depend on it.
|
||||
# [None, `bool.type`]
|
||||
"is_watchos",
|
||||
])
|
||||
|
||||
# Provider which helps to propagate minimum deployment version up the target graph.
|
||||
AppleMinDeploymentVersionInfo = provider(fields = [
|
||||
# `str.type`
|
||||
"version",
|
||||
])
|
||||
|
||||
AppleBundleResourceInfo = provider(fields = [
|
||||
"resource_output", # AppleBundleResourcePartListOutput.type
|
||||
])
|
||||
62
vendor/cxx/tools/buck/prelude/apple/apple_bundle_utility.bzl
vendored
Normal file
62
vendor/cxx/tools/buck/prelude/apple/apple_bundle_utility.bzl
vendored
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load("@prelude//utils:utils.bzl", "value_or")
|
||||
load(":apple_bundle_types.bzl", "AppleMinDeploymentVersionInfo")
|
||||
load(":apple_resource_types.bzl", "AppleResourceProcessingOptions")
|
||||
load(":apple_target_sdk_version.bzl", "get_min_deployment_version_for_node")
|
||||
load(":apple_toolchain_types.bzl", "AppleToolchainInfo")
|
||||
|
||||
# `ctx` in all functions below is expected to be of `apple_bundle` or `apple_test` rule
|
||||
|
||||
def _get_bundle_target_name(ctx: "context"):
|
||||
if hasattr(ctx.attrs, "_bundle_target_name"):
|
||||
# `apple_resource_bundle` rules are proxies for the real rules,
|
||||
# so make sure we return the real target name rather the proxy one
|
||||
return ctx.attrs._bundle_target_name
|
||||
return ctx.attrs.name
|
||||
|
||||
def get_product_name(ctx: "context") -> str.type:
|
||||
return ctx.attrs.product_name if hasattr(ctx.attrs, "product_name") and ctx.attrs.product_name != None else _get_bundle_target_name(ctx)
|
||||
|
||||
def get_extension_attr(ctx: "context") -> "":
|
||||
return ctx.attrs.extension
|
||||
|
||||
# Derives the effective deployment target for the bundle. It's
|
||||
# usually the deployment target of the binary if present,
|
||||
# otherwise it falls back to other values (see implementation).
|
||||
def get_bundle_min_target_version(ctx: "context") -> str.type:
|
||||
binary_min_version = None
|
||||
|
||||
# Could be not set for e.g. watchOS bundles which have a stub
|
||||
# binary that comes from the apple_toolchain(), not from the
|
||||
# apple_bundle() itself (i.e., binary field will be None).
|
||||
#
|
||||
# TODO(T114147746): The top-level stub bundle for a watchOS app
|
||||
# does not have the ability to set its deployment target via
|
||||
# a binary (as that field is empty). If it contains asset
|
||||
# catalogs (can it?), we need to use correct target version.
|
||||
#
|
||||
# The solution might to be support SDK version from
|
||||
# Info.plist (T110378109).
|
||||
if ctx.attrs.binary != None:
|
||||
min_version_info = ctx.attrs.binary[AppleMinDeploymentVersionInfo]
|
||||
if min_version_info != None:
|
||||
binary_min_version = min_version_info.version
|
||||
|
||||
fallback_min_version = get_min_deployment_version_for_node(ctx)
|
||||
min_version = binary_min_version or fallback_min_version
|
||||
|
||||
if min_version != None:
|
||||
return min_version
|
||||
|
||||
# TODO(T110378109): support default value from SDK `Info.plist`
|
||||
fail("Could not determine min target sdk version for bundle: {}".format(ctx.label))
|
||||
|
||||
def get_bundle_resource_processing_options(ctx: "context") -> AppleResourceProcessingOptions.type:
|
||||
compile_resources_locally = value_or(ctx.attrs._compile_resources_locally_override, ctx.attrs._apple_toolchain[AppleToolchainInfo].compile_resources_locally)
|
||||
return AppleResourceProcessingOptions(prefer_local = compile_resources_locally, allow_cache_upload = compile_resources_locally)
|
||||
18
vendor/cxx/tools/buck/prelude/apple/apple_code_signing_types.bzl
vendored
Normal file
18
vendor/cxx/tools/buck/prelude/apple/apple_code_signing_types.bzl
vendored
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
# Provider which exposes a field from `apple_binary` to `apple_bundle` as it might be used during code signing.
|
||||
AppleEntitlementsInfo = provider(fields = [
|
||||
# Optional "artifact"
|
||||
"entitlements_file",
|
||||
])
|
||||
|
||||
CodeSignType = enum(
|
||||
"skip",
|
||||
"adhoc",
|
||||
"distribution",
|
||||
)
|
||||
69
vendor/cxx/tools/buck/prelude/apple/apple_core_data.bzl
vendored
Normal file
69
vendor/cxx/tools/buck/prelude/apple/apple_core_data.bzl
vendored
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load("@prelude//apple:apple_toolchain_types.bzl", "AppleToolchainInfo")
|
||||
load(":apple_bundle_utility.bzl", "get_bundle_min_target_version", "get_bundle_resource_processing_options")
|
||||
load(":apple_core_data_types.bzl", "AppleCoreDataSpec")
|
||||
load(":apple_sdk.bzl", "get_apple_sdk_name")
|
||||
load(":resource_groups.bzl", "create_resource_graph")
|
||||
|
||||
def apple_core_data_impl(ctx: "context") -> ["provider"]:
|
||||
spec = AppleCoreDataSpec(
|
||||
path = ctx.attrs.path,
|
||||
)
|
||||
graph = create_resource_graph(
|
||||
ctx = ctx,
|
||||
labels = ctx.attrs.labels,
|
||||
deps = [],
|
||||
exported_deps = [],
|
||||
core_data_spec = spec,
|
||||
)
|
||||
return [DefaultInfo(), graph]
|
||||
|
||||
def compile_apple_core_data(ctx: "context", specs: [AppleCoreDataSpec.type], product_name: str.type) -> ["artifact", None]:
|
||||
if len(specs) == 0:
|
||||
return None
|
||||
|
||||
output = ctx.actions.declare_output("AppleCoreDataCompiled")
|
||||
|
||||
# Aggregate all the coredata momc commands together
|
||||
momc_commands = []
|
||||
for spec in specs:
|
||||
momc_command = _get_momc_command(ctx, spec, product_name, cmd_args("$TMPDIR"))
|
||||
momc_commands.append(momc_command)
|
||||
|
||||
# Sandboxing and fs isolation on RE machines results in Xcode tools failing
|
||||
# when those are working in freshly created directories in buck-out.
|
||||
# See https://fb.workplace.com/groups/1042353022615812/permalink/1872164996301273/
|
||||
# As a workaround create a directory in tmp, use it for Xcode tools, then
|
||||
# copy the result to buck-out.
|
||||
wrapper_script, _ = ctx.actions.write(
|
||||
"momc_wrapper.sh",
|
||||
[
|
||||
cmd_args('export TMPDIR="$(mktemp -d)"'),
|
||||
cmd_args(momc_commands),
|
||||
cmd_args(output, format = 'mkdir -p {} && cp -r "$TMPDIR"/ {}'),
|
||||
],
|
||||
allow_args = True,
|
||||
)
|
||||
combined_command = cmd_args(["/bin/sh", wrapper_script]).hidden(momc_commands + [output.as_output()])
|
||||
processing_options = get_bundle_resource_processing_options(ctx)
|
||||
ctx.actions.run(combined_command, prefer_local = processing_options.prefer_local, allow_cache_upload = processing_options.allow_cache_upload, category = "apple_core_data")
|
||||
return output
|
||||
|
||||
def _get_momc_command(ctx: "context", core_data_spec: AppleCoreDataSpec.type, product_name: str.type, output_directory: "cmd_args") -> "cmd_args":
|
||||
return cmd_args([
|
||||
ctx.attrs._apple_toolchain[AppleToolchainInfo].momc,
|
||||
"--sdkroot",
|
||||
ctx.attrs._apple_toolchain[AppleToolchainInfo].sdk_path,
|
||||
"--" + get_apple_sdk_name(ctx) + "-deployment-target",
|
||||
get_bundle_min_target_version(ctx),
|
||||
"--module",
|
||||
product_name,
|
||||
core_data_spec.path,
|
||||
output_directory,
|
||||
], delimiter = " ")
|
||||
10
vendor/cxx/tools/buck/prelude/apple/apple_core_data_types.bzl
vendored
Normal file
10
vendor/cxx/tools/buck/prelude/apple/apple_core_data_types.bzl
vendored
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
AppleCoreDataSpec = record(
|
||||
path = field("artifact"),
|
||||
)
|
||||
35
vendor/cxx/tools/buck/prelude/apple/apple_dsym.bzl
vendored
Normal file
35
vendor/cxx/tools/buck/prelude/apple/apple_dsym.bzl
vendored
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load("@prelude//apple:apple_toolchain_types.bzl", "AppleToolchainInfo")
|
||||
|
||||
DSYM_SUBTARGET = "dsym"
|
||||
DEBUGINFO_SUBTARGET = "debuginfo"
|
||||
|
||||
AppleDebuggableInfo = provider(fields = [
|
||||
"dsyms", # ["artifact"]
|
||||
"external_debug_info", # ["_arglike"]
|
||||
])
|
||||
|
||||
# TODO(T110672942): Things which are still unsupported:
|
||||
# - pass in dsymutil_extra_flags
|
||||
# - oso_prefix
|
||||
# - dsym_verification
|
||||
def get_apple_dsym(ctx: "context", executable: "artifact", external_debug_info: ["_arglike"], action_identifier: "string") -> "artifact":
|
||||
dsymutil = ctx.attrs._apple_toolchain[AppleToolchainInfo].dsymutil
|
||||
output = ctx.actions.declare_output("{}.dSYM".format(executable.short_path))
|
||||
|
||||
cmd = cmd_args([dsymutil, "-o", output.as_output(), executable])
|
||||
|
||||
# Mach-O executables don't contain DWARF data.
|
||||
# Instead, they contain paths to the object files which themselves contain DWARF data.
|
||||
#
|
||||
# So, those object files are needed for dsymutil to be to create the dSYM bundle.
|
||||
cmd.hidden(external_debug_info)
|
||||
ctx.actions.run(cmd, category = "apple_dsym", identifier = action_identifier)
|
||||
|
||||
return output
|
||||
1062
vendor/cxx/tools/buck/prelude/apple/apple_framework_versions.bzl
vendored
Normal file
1062
vendor/cxx/tools/buck/prelude/apple/apple_framework_versions.bzl
vendored
Normal file
File diff suppressed because it is too large
Load diff
165
vendor/cxx/tools/buck/prelude/apple/apple_frameworks.bzl
vendored
Normal file
165
vendor/cxx/tools/buck/prelude/apple/apple_frameworks.bzl
vendored
Normal file
|
|
@ -0,0 +1,165 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load("@prelude//:paths.bzl", "paths")
|
||||
load(
|
||||
"@prelude//linking:link_info.bzl",
|
||||
"FrameworksLinkable",
|
||||
"LinkArgs",
|
||||
"LinkInfo",
|
||||
"LinkInfos",
|
||||
"LinkInfosTSet",
|
||||
"LinkableType",
|
||||
"get_link_args",
|
||||
"merge_framework_linkables",
|
||||
)
|
||||
load("@prelude//utils:utils.bzl", "expect")
|
||||
load(":apple_framework_versions.bzl", "get_framework_linker_args")
|
||||
load(":apple_toolchain_types.bzl", "AppleToolchainInfo")
|
||||
|
||||
_IMPLICIT_SDKROOT_FRAMEWORK_SEARCH_PATHS = [
|
||||
"$SDKROOT/Library/Frameworks",
|
||||
"$SDKROOT/System/Library/Frameworks",
|
||||
]
|
||||
|
||||
def create_frameworks_linkable(ctx: "context") -> [FrameworksLinkable.type, None]:
|
||||
if not ctx.attrs.libraries and not ctx.attrs.frameworks:
|
||||
return None
|
||||
|
||||
return FrameworksLinkable(
|
||||
library_names = [_library_name(x) for x in ctx.attrs.libraries],
|
||||
unresolved_framework_paths = _get_non_sdk_unresolved_framework_directories(ctx.attrs.frameworks),
|
||||
framework_names = [to_framework_name(x) for x in ctx.attrs.frameworks],
|
||||
)
|
||||
|
||||
def _get_apple_frameworks_linker_flags(ctx: "context", linkable: [FrameworksLinkable.type, None]) -> "cmd_args":
|
||||
if not linkable:
|
||||
return cmd_args()
|
||||
|
||||
expanded_frameworks_paths = _expand_sdk_framework_paths(ctx, linkable.unresolved_framework_paths)
|
||||
flags = _get_framework_search_path_flags(expanded_frameworks_paths)
|
||||
flags.add(get_framework_linker_args(ctx, linkable.framework_names))
|
||||
|
||||
for library_name in linkable.library_names:
|
||||
flags.add("-l" + library_name)
|
||||
|
||||
return flags
|
||||
|
||||
def get_framework_search_path_flags(ctx: "context") -> "cmd_args":
|
||||
unresolved_framework_dirs = _get_non_sdk_unresolved_framework_directories(ctx.attrs.frameworks)
|
||||
expanded_framework_dirs = _expand_sdk_framework_paths(ctx, unresolved_framework_dirs)
|
||||
return _get_framework_search_path_flags(expanded_framework_dirs)
|
||||
|
||||
def _get_framework_search_path_flags(frameworks: ["cmd_args"]) -> "cmd_args":
|
||||
flags = cmd_args()
|
||||
for directory in frameworks:
|
||||
flags.add(["-F", directory])
|
||||
|
||||
return flags
|
||||
|
||||
def _get_non_sdk_unresolved_framework_directories(frameworks: [""]) -> [""]:
|
||||
# We don't want to include SDK directories as those are already added via `isysroot` flag in toolchain definition.
|
||||
# Adding those directly via `-F` will break building Catalyst applications as frameworks from support directory
|
||||
# won't be found and those for macOS platform will be used.
|
||||
return dedupe(filter(None, [_non_sdk_unresolved_framework_directory(x) for x in frameworks]))
|
||||
|
||||
def to_framework_name(framework_path: str.type) -> str.type:
|
||||
name, ext = paths.split_extension(paths.basename(framework_path))
|
||||
expect(ext == ".framework", "framework `{}` missing `.framework` suffix", framework_path)
|
||||
return name
|
||||
|
||||
def _library_name(library: str.type) -> str.type:
|
||||
name = paths.basename(library)
|
||||
if not name.startswith("lib"):
|
||||
fail("unexpected library: {}".format(library))
|
||||
return paths.split_extension(name[3:])[0]
|
||||
|
||||
def _expand_sdk_framework_paths(ctx: "context", unresolved_framework_paths: [str.type]) -> ["cmd_args"]:
|
||||
return [_expand_sdk_framework_path(ctx, unresolved_framework_path) for unresolved_framework_path in unresolved_framework_paths]
|
||||
|
||||
def _expand_sdk_framework_path(ctx: "context", framework_path: str.type) -> "cmd_args":
|
||||
apple_toolchain_info = ctx.attrs._apple_toolchain[AppleToolchainInfo]
|
||||
path_expansion_map = {
|
||||
"$PLATFORM_DIR/": apple_toolchain_info.platform_path,
|
||||
"$SDKROOT/": apple_toolchain_info.sdk_path,
|
||||
}
|
||||
|
||||
for (trailing_path_variable, path_value) in path_expansion_map.items():
|
||||
(before, separator, relative_path) = framework_path.partition(trailing_path_variable)
|
||||
if separator == trailing_path_variable:
|
||||
if len(before) > 0:
|
||||
fail("Framework symbolic path not anchored at the beginning, tried expanding `{}`".format(framework_path))
|
||||
if relative_path.count("$") > 0:
|
||||
fail("Framework path contains multiple symbolic paths, tried expanding `{}`".format(framework_path))
|
||||
if len(relative_path) == 0:
|
||||
fail("Framework symbolic path contains no relative path to expand, tried expanding `{}`, relative path: `{}`, before: `{}`, separator `{}`".format(framework_path, relative_path, before, separator))
|
||||
|
||||
return cmd_args([path_value, relative_path], delimiter = "/")
|
||||
|
||||
if framework_path.find("$") == 0:
|
||||
fail("Failed to expand framework path: {}".format(framework_path))
|
||||
|
||||
return cmd_args(framework_path)
|
||||
|
||||
def _non_sdk_unresolved_framework_directory(framework_path: str.type) -> [str.type, None]:
|
||||
# We must only drop any framework paths that are part of the implicit
|
||||
# framework search paths in the linker + compiler, all other paths
|
||||
# must be expanded and included as part of the command.
|
||||
for implicit_search_path in _IMPLICIT_SDKROOT_FRAMEWORK_SEARCH_PATHS:
|
||||
if framework_path.find(implicit_search_path) == 0:
|
||||
return None
|
||||
return paths.dirname(framework_path)
|
||||
|
||||
def build_link_args_with_deduped_framework_flags(
|
||||
ctx: "context",
|
||||
info: "MergedLinkInfo",
|
||||
frameworks_linkable: ["FrameworksLinkable", None],
|
||||
link_style: "LinkStyle",
|
||||
prefer_stripped: bool.type = False) -> LinkArgs.type:
|
||||
frameworks_link_info = _link_info_from_frameworks_linkable(ctx, [info.frameworks[link_style], frameworks_linkable])
|
||||
if not frameworks_link_info:
|
||||
return get_link_args(info, link_style, prefer_stripped)
|
||||
|
||||
return LinkArgs(
|
||||
tset = (ctx.actions.tset(
|
||||
LinkInfosTSet,
|
||||
value = LinkInfos(default = frameworks_link_info, stripped = frameworks_link_info),
|
||||
children = [info._infos[link_style]],
|
||||
), prefer_stripped),
|
||||
)
|
||||
|
||||
def get_frameworks_link_info_by_deduping_link_infos(
|
||||
ctx: "context",
|
||||
infos: [[LinkInfo.type, None]],
|
||||
framework_linkable: [FrameworksLinkable.type, None]) -> [LinkInfo.type, None]:
|
||||
# When building a framework or executable, all frameworks used by the statically-linked
|
||||
# deps in the subtree need to be linked.
|
||||
#
|
||||
# Without deduping, we've seen the linking step fail because the argsfile
|
||||
# exceeds the acceptable size by the linker.
|
||||
framework_linkables = _extract_framework_linkables(infos)
|
||||
if framework_linkable:
|
||||
framework_linkables.append(framework_linkable)
|
||||
|
||||
return _link_info_from_frameworks_linkable(ctx, framework_linkables)
|
||||
|
||||
def _extract_framework_linkables(link_infos: [[LinkInfo.type], None]) -> [FrameworksLinkable.type]:
|
||||
frameworks_type = LinkableType("frameworks")
|
||||
|
||||
linkables = []
|
||||
for info in link_infos:
|
||||
for linkable in info.linkables:
|
||||
if linkable._type == frameworks_type:
|
||||
linkables.append(linkable)
|
||||
|
||||
return linkables
|
||||
|
||||
def _link_info_from_frameworks_linkable(ctx: "context", framework_linkables: [[FrameworksLinkable.type, None]]) -> [LinkInfo.type, None]:
|
||||
framework_link_args = _get_apple_frameworks_linker_flags(ctx, merge_framework_linkables(framework_linkables))
|
||||
return LinkInfo(
|
||||
pre_flags = [framework_link_args],
|
||||
) if framework_link_args else None
|
||||
139
vendor/cxx/tools/buck/prelude/apple/apple_info_plist.bzl
vendored
Normal file
139
vendor/cxx/tools/buck/prelude/apple/apple_info_plist.bzl
vendored
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load(":apple_bundle_destination.bzl", "AppleBundleDestination")
|
||||
load(":apple_bundle_part.bzl", "AppleBundlePart")
|
||||
load(":apple_bundle_utility.bzl", "get_bundle_min_target_version", "get_product_name")
|
||||
load(":apple_sdk.bzl", "get_apple_sdk_name")
|
||||
load(
|
||||
":apple_sdk_metadata.bzl",
|
||||
"AppleSdkMetadata", # @unused Used as a type
|
||||
"MacOSXCatalystSdkMetadata",
|
||||
"MacOSXSdkMetadata",
|
||||
"WatchOSSdkMetadata",
|
||||
"WatchSimulatorSdkMetadata",
|
||||
"get_apple_sdk_metadata_for_sdk_name",
|
||||
)
|
||||
load(":apple_toolchain_types.bzl", "AppleToolchainInfo", "AppleToolsInfo")
|
||||
|
||||
def process_info_plist(ctx: "context", override_input: ["artifact", None]) -> AppleBundlePart.type:
|
||||
input = _preprocess_info_plist(ctx)
|
||||
output = ctx.actions.declare_output("Info.plist")
|
||||
additional_keys = _additional_keys_as_json_file(ctx)
|
||||
override_keys = _override_keys_as_json_file(ctx)
|
||||
process_plist(
|
||||
ctx = ctx,
|
||||
input = input,
|
||||
output = output.as_output(),
|
||||
override_input = override_input,
|
||||
additional_keys = additional_keys,
|
||||
override_keys = override_keys,
|
||||
)
|
||||
return AppleBundlePart(source = output, destination = AppleBundleDestination("metadata"))
|
||||
|
||||
def _get_plist_run_options() -> {str.type: bool.type}:
|
||||
return {
|
||||
# Output is deterministic, so can be cached
|
||||
"allow_cache_upload": True,
|
||||
# plist generation is cheap and fast, RE network overhead not worth it
|
||||
"prefer_local": True,
|
||||
}
|
||||
|
||||
def _preprocess_info_plist(ctx: "context") -> "artifact":
|
||||
input = ctx.attrs.info_plist
|
||||
output = ctx.actions.declare_output("PreprocessedInfo.plist")
|
||||
substitutions_json = _plist_substitutions_as_json_file(ctx)
|
||||
apple_tools = ctx.attrs._apple_tools[AppleToolsInfo]
|
||||
processor = apple_tools.info_plist_processor
|
||||
command = cmd_args([
|
||||
processor,
|
||||
"preprocess",
|
||||
"--input",
|
||||
input,
|
||||
"--output",
|
||||
output.as_output(),
|
||||
"--product-name",
|
||||
get_product_name(ctx),
|
||||
])
|
||||
if substitutions_json != None:
|
||||
command.add(["--substitutions-json", substitutions_json])
|
||||
ctx.actions.run(command, category = "apple_preprocess_info_plist", **_get_plist_run_options())
|
||||
return output
|
||||
|
||||
def _plist_substitutions_as_json_file(ctx: "context") -> ["artifact", None]:
|
||||
info_plist_substitutions = ctx.attrs.info_plist_substitutions
|
||||
if not info_plist_substitutions:
|
||||
return None
|
||||
|
||||
substitutions_json = ctx.actions.write_json("plist_substitutions.json", info_plist_substitutions)
|
||||
return substitutions_json
|
||||
|
||||
def process_plist(ctx: "context", input: "artifact", output: "output_artifact", override_input: ["artifact", None] = None, additional_keys: ["artifact", None] = None, override_keys: ["artifact", None] = None, action_id: [str.type, None] = None):
|
||||
apple_tools = ctx.attrs._apple_tools[AppleToolsInfo]
|
||||
processor = apple_tools.info_plist_processor
|
||||
override_input_arguments = ["--override-input", override_input] if override_input != None else []
|
||||
additional_keys_arguments = ["--additional-keys", additional_keys] if additional_keys != None else []
|
||||
override_keys_arguments = ["--override-keys", override_keys] if override_keys != None else []
|
||||
command = cmd_args([
|
||||
processor,
|
||||
"process",
|
||||
"--input",
|
||||
input,
|
||||
"--output",
|
||||
output,
|
||||
] + override_input_arguments + additional_keys_arguments + override_keys_arguments)
|
||||
ctx.actions.run(command, category = "apple_process_info_plist", identifier = action_id or input.basename, **_get_plist_run_options())
|
||||
|
||||
def _additional_keys_as_json_file(ctx: "context") -> "artifact":
|
||||
additional_keys = _info_plist_additional_keys(ctx)
|
||||
return ctx.actions.write_json("plist_additional.json", additional_keys)
|
||||
|
||||
def _info_plist_additional_keys(ctx: "context") -> {str.type: ""}:
|
||||
sdk_name = get_apple_sdk_name(ctx)
|
||||
sdk_metadata = get_apple_sdk_metadata_for_sdk_name(sdk_name)
|
||||
result = _extra_mac_info_plist_keys(sdk_metadata, ctx.attrs.extension)
|
||||
result["CFBundleSupportedPlatforms"] = sdk_metadata.info_plist_supported_platforms_values
|
||||
result["DTPlatformName"] = sdk_name
|
||||
sdk_version = ctx.attrs._apple_toolchain[AppleToolchainInfo].sdk_version
|
||||
if sdk_version:
|
||||
result["DTPlatformVersion"] = sdk_version
|
||||
result["DTSDKName"] = sdk_name + sdk_version
|
||||
sdk_build_version = ctx.attrs._apple_toolchain[AppleToolchainInfo].sdk_build_version
|
||||
if sdk_build_version:
|
||||
result["DTPlatformBuild"] = sdk_build_version
|
||||
result["DTSDKBuild"] = sdk_build_version
|
||||
xcode_build_version = ctx.attrs._apple_toolchain[AppleToolchainInfo].xcode_build_version
|
||||
if xcode_build_version:
|
||||
result["DTXcodeBuild"] = xcode_build_version
|
||||
xcode_version = ctx.attrs._apple_toolchain[AppleToolchainInfo].xcode_version
|
||||
if xcode_version:
|
||||
result["DTXcode"] = xcode_version
|
||||
result[sdk_metadata.min_version_plist_info_key] = get_bundle_min_target_version(ctx)
|
||||
return result
|
||||
|
||||
def _extra_mac_info_plist_keys(sdk_metadata: AppleSdkMetadata.type, extension: str.type) -> {str.type: ""}:
|
||||
if sdk_metadata.name == MacOSXSdkMetadata.name and extension == "xpc":
|
||||
return {
|
||||
"NSHighResolutionCapable": True,
|
||||
"NSSupportsAutomaticGraphicsSwitching": True,
|
||||
}
|
||||
else:
|
||||
return {}
|
||||
|
||||
def _override_keys_as_json_file(ctx: "context") -> "artifact":
|
||||
override_keys = _info_plist_override_keys(ctx)
|
||||
return ctx.actions.write_json("plist_override.json", override_keys)
|
||||
|
||||
def _info_plist_override_keys(ctx: "context") -> {str.type: ""}:
|
||||
sdk_name = get_apple_sdk_name(ctx)
|
||||
result = {}
|
||||
if sdk_name == MacOSXSdkMetadata.name:
|
||||
if ctx.attrs.extension != "xpc":
|
||||
result["LSRequiresIPhoneOS"] = False
|
||||
elif sdk_name not in [WatchOSSdkMetadata.name, WatchSimulatorSdkMetadata.name, MacOSXCatalystSdkMetadata.name]:
|
||||
result["LSRequiresIPhoneOS"] = True
|
||||
return result
|
||||
60
vendor/cxx/tools/buck/prelude/apple/apple_info_plist_substitutions_parsing.bzl
vendored
Normal file
60
vendor/cxx/tools/buck/prelude/apple/apple_info_plist_substitutions_parsing.bzl
vendored
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
# `apple_bundle.info_plist_substitutions` might contain `CODE_SIGN_ENTITLEMENTS` key which (as per v1 documentation):
|
||||
#
|
||||
# > Code signing will embed entitlements pointed to by the entitlements_file arg in the bundle's apple_binary.
|
||||
# > This is the preferred way to specify entitlements when building with Buck.
|
||||
# > If the entitlements file is not present, it falls back to the CODE_SIGN_ENTITLEMENTS entry in info_plist_substitutions.
|
||||
#
|
||||
# In order to properly depend on this fallback entitlements file (and manipulate it) we have to convert this text entry into the source artifact.
|
||||
# We only can do that on macro layer, hence the purpose of the following code.
|
||||
|
||||
_SOURCE_ROOT_PREFIX = "$(SOURCE_ROOT)/"
|
||||
_CODE_SIGN_ENTITLEMENTS_KEY = "CODE_SIGN_ENTITLEMENTS"
|
||||
|
||||
def _find_first_variable(string: str.type) -> [(str.type, (str.type, str.type)), None]:
|
||||
"""
|
||||
If variable like `$(FOO)` is not found in `string` returns `None`, else returns tuple
|
||||
with first element equal to variable name (e.g. `FOO`) and second element equal to tuple
|
||||
of part before and after this variable.
|
||||
"""
|
||||
expansion_start = "$("
|
||||
expansion_end = ")"
|
||||
variable_start = string.find(expansion_start)
|
||||
if variable_start == -1:
|
||||
return None
|
||||
variable_end = string.find(expansion_end, variable_start)
|
||||
if variable_end == -1:
|
||||
fail("Expected variable expansion in string: `{}`".format(string))
|
||||
variable = string[variable_start + len(expansion_start):variable_end - len(expansion_end) + 1]
|
||||
prefix = string[:variable_start]
|
||||
suffix = string[variable_end + 1:]
|
||||
return (variable, (prefix, suffix))
|
||||
|
||||
def _expand_codesign_entitlements_path(info_plist_substitutions: {str.type: str.type}, path: str.type) -> str.type:
|
||||
path = path.strip()
|
||||
for _ in range(100):
|
||||
if path.startswith(_SOURCE_ROOT_PREFIX):
|
||||
path = path[len(_SOURCE_ROOT_PREFIX):]
|
||||
maybe_variable = _find_first_variable(path)
|
||||
if not maybe_variable:
|
||||
return path
|
||||
(key, (prefix, suffix)) = maybe_variable
|
||||
maybe_value = info_plist_substitutions.get(key)
|
||||
if not maybe_value:
|
||||
fail("Expected to find value for `{}` in `info_plist_substitutions` dictionary `{}`".format(key, info_plist_substitutions))
|
||||
path = prefix + maybe_value + suffix
|
||||
fail("Too many iteration (loop might be present) to expand `{}` with substitutions `{}`".format(path, info_plist_substitutions))
|
||||
|
||||
def parse_codesign_entitlements(info_plist_substitutions: [{str.type: str.type}, None]) -> [str.type, None]:
|
||||
if not info_plist_substitutions:
|
||||
return None
|
||||
maybe_path = info_plist_substitutions.get(_CODE_SIGN_ENTITLEMENTS_KEY)
|
||||
if not maybe_path:
|
||||
return None
|
||||
return _expand_codesign_entitlements_path(info_plist_substitutions, maybe_path)
|
||||
216
vendor/cxx/tools/buck/prelude/apple/apple_library.bzl
vendored
Normal file
216
vendor/cxx/tools/buck/prelude/apple/apple_library.bzl
vendored
Normal file
|
|
@ -0,0 +1,216 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load("@prelude//apple:apple_dsym.bzl", "AppleDebuggableInfo", "DEBUGINFO_SUBTARGET", "DSYM_SUBTARGET", "get_apple_dsym")
|
||||
load("@prelude//apple:apple_stripping.bzl", "apple_strip_args")
|
||||
load("@prelude//apple:swift_compilation.bzl", "compile_swift", "get_swift_dependency_info", "get_swift_pcm_compile_info")
|
||||
load("@prelude//cxx:cxx.bzl", "get_srcs_with_flags")
|
||||
load("@prelude//cxx:cxx_library.bzl", "cxx_library_parameterized")
|
||||
load("@prelude//cxx:cxx_library_utility.bzl", "cxx_attr_deps", "cxx_attr_exported_deps")
|
||||
load("@prelude//cxx:cxx_types.bzl", "CxxRuleAdditionalParams", "CxxRuleConstructorParams", "CxxRuleProviderParams", "CxxRuleSubTargetParams")
|
||||
load("@prelude//cxx:headers.bzl", "cxx_attr_exported_headers")
|
||||
load(
|
||||
"@prelude//cxx:linker.bzl",
|
||||
"SharedLibraryFlagOverrides",
|
||||
)
|
||||
load(
|
||||
"@prelude//cxx:preprocessor.bzl",
|
||||
"CPreprocessor",
|
||||
)
|
||||
load("@prelude//linking:link_info.bzl", "LinkStyle")
|
||||
load(":apple_bundle_types.bzl", "AppleMinDeploymentVersionInfo")
|
||||
load(":apple_frameworks.bzl", "get_framework_search_path_flags")
|
||||
load(":apple_link_postprocessor.bzl", "get_apple_link_postprocessor")
|
||||
load(":apple_modular_utility.bzl", "MODULE_CACHE_PATH")
|
||||
load(":apple_target_sdk_version.bzl", "get_min_deployment_version_for_node", "get_min_deployment_version_target_linker_flags", "get_min_deployment_version_target_preprocessor_flags")
|
||||
load(":apple_utility.bzl", "get_apple_cxx_headers_layout", "get_module_name")
|
||||
load(":modulemap.bzl", "preprocessor_info_for_modulemap")
|
||||
load(":resource_groups.bzl", "create_resource_graph")
|
||||
load(":xcode.bzl", "apple_populate_xcode_attributes")
|
||||
|
||||
AppleLibraryAdditionalParams = record(
|
||||
# Name of the top level rule utilizing the apple_library rule.
|
||||
rule_type = str.type,
|
||||
# Extra flags to be passed to the linker.
|
||||
extra_exported_link_flags = field(["_arglike"], []),
|
||||
# Extra flags to be passed to the Swift compiler.
|
||||
extra_swift_compiler_flags = field(["_arglike"], []),
|
||||
# Linker flags that tell the linker to create shared libraries, overriding the default shared library flags.
|
||||
# e.g. when building Apple tests, we want to link with `-bundle` instead of `-shared` to allow
|
||||
# linking against the bundle loader.
|
||||
shared_library_flags = field([SharedLibraryFlagOverrides.type, None], None),
|
||||
# Function to use for setting Xcode attributes for the Xcode data sub target.
|
||||
populate_xcode_attributes_func = field("function", apple_populate_xcode_attributes),
|
||||
# Define which sub targets to generate.
|
||||
generate_sub_targets = field(CxxRuleSubTargetParams.type, CxxRuleSubTargetParams()),
|
||||
# Define which providers to generate.
|
||||
generate_providers = field(CxxRuleProviderParams.type, CxxRuleProviderParams()),
|
||||
# Forces link group linking logic, even when there's no mapping. Link group linking
|
||||
# without a mapping is equivalent to statically linking the whole transitive dep graph.
|
||||
force_link_group_linking = field(bool.type, False),
|
||||
)
|
||||
|
||||
def apple_library_impl(ctx: "context") -> ["provider"]:
|
||||
constructor_params, swift_providers, exported_pre = apple_library_rule_constructor_params_and_swift_providers(ctx, AppleLibraryAdditionalParams(rule_type = "apple_library"))
|
||||
|
||||
resource_graph = create_resource_graph(
|
||||
ctx = ctx,
|
||||
labels = ctx.attrs.labels,
|
||||
deps = cxx_attr_deps(ctx),
|
||||
exported_deps = cxx_attr_exported_deps(ctx),
|
||||
)
|
||||
|
||||
output = cxx_library_parameterized(ctx, constructor_params)
|
||||
swift_pcm_compile = get_swift_pcm_compile_info(ctx, output.propagated_exported_preprocessor_info, exported_pre)
|
||||
|
||||
providers = output.providers + [resource_graph] + swift_providers + ([swift_pcm_compile] if swift_pcm_compile else [])
|
||||
return providers
|
||||
|
||||
def apple_library_rule_constructor_params_and_swift_providers(ctx: "context", params: AppleLibraryAdditionalParams.type) -> (CxxRuleConstructorParams.type, ["provider"], [CPreprocessor.type, None]):
|
||||
cxx_srcs, swift_srcs = _filter_swift_srcs(ctx)
|
||||
|
||||
# First create a modulemap if necessary. This is required for importing
|
||||
# ObjC code in Swift so must be done before Swift compilation.
|
||||
exported_hdrs = cxx_attr_exported_headers(ctx, get_apple_cxx_headers_layout(ctx))
|
||||
if (ctx.attrs.modular or swift_srcs) and exported_hdrs:
|
||||
modulemap_pre = preprocessor_info_for_modulemap(ctx, "exported", exported_hdrs, None)
|
||||
else:
|
||||
modulemap_pre = None
|
||||
|
||||
swift_compile = compile_swift(ctx, swift_srcs, exported_hdrs, modulemap_pre, params.extra_swift_compiler_flags)
|
||||
swift_object_files = swift_compile.object_files if swift_compile else []
|
||||
|
||||
swift_pre = CPreprocessor()
|
||||
if swift_compile:
|
||||
# If we have Swift we export the extended modulemap that includes
|
||||
# the ObjC exported headers and the -Swift.h header.
|
||||
exported_pre = swift_compile.exported_pre
|
||||
|
||||
# We also include the -Swift.h header to this libraries preprocessor
|
||||
# info, so that we can import it unprefixed in this module.
|
||||
swift_pre = swift_compile.pre
|
||||
elif modulemap_pre:
|
||||
# Otherwise if this library is modular we export a modulemap of
|
||||
# the ObjC exported headers.
|
||||
exported_pre = modulemap_pre
|
||||
else:
|
||||
exported_pre = None
|
||||
|
||||
swift_providers = swift_compile.providers if swift_compile else [get_swift_dependency_info(ctx, exported_pre, None)]
|
||||
swift_argsfile = swift_compile.swift_argsfile if swift_compile else None
|
||||
|
||||
modular_pre = CPreprocessor(
|
||||
uses_modules = ctx.attrs.uses_modules,
|
||||
modular_args = [
|
||||
"-fcxx-modules",
|
||||
"-fmodules",
|
||||
"-fmodule-name=" + get_module_name(ctx),
|
||||
"-fmodules-cache-path=" + MODULE_CACHE_PATH,
|
||||
# TODO(T123756899): We have to use this hack to make compilation work
|
||||
# when Clang modules are enabled and using toolchains. That's because
|
||||
# resource-dir is passed as a relative path (so that no abs paths appear
|
||||
# in any .pcm). The compiler will then expand and generate #include paths
|
||||
# that won't work unless we have the directive below.
|
||||
"-I.",
|
||||
],
|
||||
)
|
||||
|
||||
framework_search_path_pre = CPreprocessor(
|
||||
args = [get_framework_search_path_flags(ctx)],
|
||||
)
|
||||
return CxxRuleConstructorParams(
|
||||
rule_type = params.rule_type,
|
||||
is_test = (params.rule_type == "apple_test"),
|
||||
headers_layout = get_apple_cxx_headers_layout(ctx),
|
||||
extra_exported_link_flags = params.extra_exported_link_flags,
|
||||
extra_link_flags = [_get_linker_flags(ctx, swift_providers)],
|
||||
extra_link_input = swift_object_files,
|
||||
extra_preprocessors = get_min_deployment_version_target_preprocessor_flags(ctx) + [framework_search_path_pre, swift_pre, modular_pre],
|
||||
extra_exported_preprocessors = filter(None, [exported_pre]),
|
||||
srcs = cxx_srcs,
|
||||
additional = CxxRuleAdditionalParams(
|
||||
srcs = swift_srcs,
|
||||
argsfiles = [swift_argsfile] if swift_argsfile else [],
|
||||
# We need to add any swift modules that we include in the link, as
|
||||
# these will end up as `N_AST` entries that `dsymutil` will need to
|
||||
# follow.
|
||||
external_debug_info = [_get_transitive_swiftmodule_paths(swift_providers)],
|
||||
),
|
||||
link_style_sub_targets_and_providers_factory = _get_shared_link_style_sub_targets_and_providers,
|
||||
shared_library_flags = params.shared_library_flags,
|
||||
# apple_library's 'stripped' arg only applies to shared subtargets, or,
|
||||
# targets with 'preferred_linkage = "shared"'
|
||||
strip_executable = ctx.attrs.stripped,
|
||||
strip_args_factory = apple_strip_args,
|
||||
force_link_group_linking = params.force_link_group_linking,
|
||||
cxx_populate_xcode_attributes_func = lambda local_ctx, **kwargs: _xcode_populate_attributes(ctx = local_ctx, swift_argsfile = swift_argsfile, populate_xcode_attributes_func = params.populate_xcode_attributes_func, **kwargs),
|
||||
generate_sub_targets = params.generate_sub_targets,
|
||||
generate_providers = params.generate_providers,
|
||||
link_postprocessor = get_apple_link_postprocessor(ctx),
|
||||
), swift_providers, exported_pre
|
||||
|
||||
def _filter_swift_srcs(ctx: "context") -> (["CxxSrcWithFlags"], ["CxxSrcWithFlags"]):
|
||||
cxx_srcs = []
|
||||
swift_srcs = []
|
||||
for s in get_srcs_with_flags(ctx):
|
||||
if s.file.extension == ".swift":
|
||||
swift_srcs.append(s)
|
||||
else:
|
||||
cxx_srcs.append(s)
|
||||
|
||||
return cxx_srcs, swift_srcs
|
||||
|
||||
def _get_shared_link_style_sub_targets_and_providers(
|
||||
link_style: LinkStyle.type,
|
||||
ctx: "context",
|
||||
executable: "artifact",
|
||||
external_debug_info: ["_arglike"],
|
||||
_dwp: ["artifact", None]) -> ({str.type: ["provider"]}, ["provider"]):
|
||||
if link_style != LinkStyle("shared"):
|
||||
return ({}, [])
|
||||
|
||||
min_version = get_min_deployment_version_for_node(ctx)
|
||||
min_version_providers = [AppleMinDeploymentVersionInfo(version = min_version)] if min_version != None else []
|
||||
|
||||
dsym_artifact = get_apple_dsym(
|
||||
ctx = ctx,
|
||||
executable = executable,
|
||||
external_debug_info = external_debug_info,
|
||||
action_identifier = executable.short_path,
|
||||
)
|
||||
return ({
|
||||
DSYM_SUBTARGET: [DefaultInfo(default_outputs = [dsym_artifact])],
|
||||
DEBUGINFO_SUBTARGET: [DefaultInfo(other_outputs = external_debug_info)],
|
||||
}, [AppleDebuggableInfo(dsyms = [dsym_artifact], external_debug_info = external_debug_info)] + min_version_providers)
|
||||
|
||||
def _get_transitive_swiftmodule_paths(swift_providers: ["provider"]) -> "cmd_args":
|
||||
cmd = cmd_args()
|
||||
for p in swift_providers:
|
||||
if hasattr(p, "transitive_swiftmodule_paths"):
|
||||
cmd.add(p.transitive_swiftmodule_paths.project_as_args("hidden"))
|
||||
return cmd
|
||||
|
||||
def _get_linker_flags(ctx: "context", swift_providers: ["provider"]) -> "cmd_args":
|
||||
cmd = cmd_args(get_min_deployment_version_target_linker_flags(ctx))
|
||||
for p in swift_providers:
|
||||
if hasattr(p, "transitive_swiftmodule_paths"):
|
||||
cmd.add(p.transitive_swiftmodule_paths.project_as_args("linker_args"))
|
||||
|
||||
return cmd
|
||||
|
||||
def _xcode_populate_attributes(
|
||||
ctx,
|
||||
srcs: ["CxxSrcWithFlags"],
|
||||
argsfiles_by_ext: {str.type: "artifact"},
|
||||
swift_argsfile: ["CxxAdditionalArgsfileParams", None],
|
||||
populate_xcode_attributes_func: "function",
|
||||
**_kwargs) -> {str.type: ""}:
|
||||
if swift_argsfile:
|
||||
argsfiles_by_ext[swift_argsfile.extension] = swift_argsfile.file
|
||||
|
||||
data = populate_xcode_attributes_func(ctx, srcs = srcs, argsfiles_by_ext = argsfiles_by_ext, product_name = ctx.attrs.name)
|
||||
return data
|
||||
11
vendor/cxx/tools/buck/prelude/apple/apple_link_postprocessor.bzl
vendored
Normal file
11
vendor/cxx/tools/buck/prelude/apple/apple_link_postprocessor.bzl
vendored
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
def get_apple_link_postprocessor(ctx):
|
||||
if ctx.attrs.link_postprocessor:
|
||||
return cmd_args(ctx.attrs.link_postprocessor[RunInfo])
|
||||
return None
|
||||
43
vendor/cxx/tools/buck/prelude/apple/apple_macro_layer.bzl
vendored
Normal file
43
vendor/cxx/tools/buck/prelude/apple/apple_macro_layer.bzl
vendored
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load(
|
||||
":apple_rules_impl_utility.bzl",
|
||||
"APPLE_ARCHIVE_OBJECTS_LOCALLY_OVERRIDE_ATTR_NAME",
|
||||
"APPLE_LINK_BINARIES_LOCALLY_OVERRIDE_ATTR_NAME",
|
||||
"APPLE_LINK_LIBRARIES_LOCALLY_OVERRIDE_ATTR_NAME",
|
||||
)
|
||||
|
||||
_APPLE_LIBRARY_LOCAL_EXECUTION_OVERRIDES = {
|
||||
APPLE_LINK_LIBRARIES_LOCALLY_OVERRIDE_ATTR_NAME: ("apple", "link_libraries_locally_override"),
|
||||
APPLE_ARCHIVE_OBJECTS_LOCALLY_OVERRIDE_ATTR_NAME: ("apple", "archive_objects_locally_override"),
|
||||
}
|
||||
|
||||
_APPLE_BINARY_LOCAL_EXECUTION_OVERRIDES = {
|
||||
APPLE_LINK_BINARIES_LOCALLY_OVERRIDE_ATTR_NAME: ("apple", "link_binaries_locally_override"),
|
||||
}
|
||||
|
||||
def apple_macro_layer_set_bool_override_attrs_from_config(attrib_map: {str.type: (str.type, str.type)}) -> {str.type: "selector"}:
|
||||
attribs = {}
|
||||
for (attrib_name, (config_section, config_key)) in attrib_map.items():
|
||||
config_value = read_config(config_section, config_key, None)
|
||||
if config_value != None:
|
||||
config_truth_value = config_value.lower() == "true"
|
||||
attribs[attrib_name] = select({
|
||||
"DEFAULT": config_truth_value,
|
||||
# Do not set attribute value for host tools
|
||||
"ovr_config//platform/macos/constraints:execution-platform-transitioned": None,
|
||||
})
|
||||
return attribs
|
||||
|
||||
def apple_library_macro_impl(apple_library_rule = None, **kwargs):
|
||||
kwargs.update(apple_macro_layer_set_bool_override_attrs_from_config(_APPLE_LIBRARY_LOCAL_EXECUTION_OVERRIDES))
|
||||
apple_library_rule(**kwargs)
|
||||
|
||||
def apple_binary_macro_impl(apple_binary_rule = None, **kwargs):
|
||||
kwargs.update(apple_macro_layer_set_bool_override_attrs_from_config(_APPLE_BINARY_LOCAL_EXECUTION_OVERRIDES))
|
||||
apple_binary_rule(**kwargs)
|
||||
14
vendor/cxx/tools/buck/prelude/apple/apple_modular_utility.bzl
vendored
Normal file
14
vendor/cxx/tools/buck/prelude/apple/apple_modular_utility.bzl
vendored
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
# We use a fixed module cache location. This works around issues with
|
||||
# multi-user setups with MobileOnDemand and allows us to share the
|
||||
# module cache with Xcode, LLDB and arc focus.
|
||||
#
|
||||
# TODO(T123737676): This needs to be changed to use $TMPDIR in a
|
||||
# wrapper for modular clang compilation.
|
||||
MODULE_CACHE_PATH = "/tmp/buck-module-cache"
|
||||
23
vendor/cxx/tools/buck/prelude/apple/apple_package.bzl
vendored
Normal file
23
vendor/cxx/tools/buck/prelude/apple/apple_package.bzl
vendored
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
def apple_package_impl(ctx: "context") -> ["provider"]:
|
||||
bundle = ctx.attrs.bundle
|
||||
ipa_name = "{}.ipa".format(bundle.label.name)
|
||||
app = bundle[DefaultInfo].default_outputs[0]
|
||||
|
||||
payload = ctx.actions.copy_file("Payload", app)
|
||||
|
||||
package = ctx.actions.declare_output(ipa_name)
|
||||
|
||||
# TODO(T96496412): Add support for compression levels and SwiftSupport
|
||||
# TODO(T110378117): Pull this into a shared zip utility function
|
||||
|
||||
zip = cmd_args(["(cd \"", cmd_args(payload).parent(), "\" && zip -X -r - \"", payload.basename, "\") > ", package.as_output()], delimiter = "")
|
||||
ctx.actions.run(["sh", "-c", zip], category = "apple_package_zip")
|
||||
|
||||
return [DefaultInfo(default_outputs = [package])]
|
||||
29
vendor/cxx/tools/buck/prelude/apple/apple_resource.bzl
vendored
Normal file
29
vendor/cxx/tools/buck/prelude/apple/apple_resource.bzl
vendored
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load(":apple_resource_types.bzl", "AppleResourceDestination", "AppleResourceSpec")
|
||||
load(":resource_groups.bzl", "create_resource_graph")
|
||||
|
||||
def apple_resource_impl(ctx: "context") -> ["provider"]:
|
||||
destination = ctx.attrs.destination or "resources"
|
||||
resource_spec = AppleResourceSpec(
|
||||
files = ctx.attrs.files,
|
||||
dirs = ctx.attrs.dirs,
|
||||
content_dirs = ctx.attrs.content_dirs,
|
||||
destination = AppleResourceDestination(destination),
|
||||
variant_files = ctx.attrs.variants or [],
|
||||
named_variant_files = ctx.attrs.named_variants or {},
|
||||
codesign_files_on_copy = ctx.attrs.codesign_on_copy,
|
||||
)
|
||||
graph = create_resource_graph(
|
||||
ctx = ctx,
|
||||
labels = ctx.attrs.labels,
|
||||
deps = [],
|
||||
exported_deps = [],
|
||||
resource_spec = resource_spec,
|
||||
)
|
||||
return [DefaultInfo(), graph]
|
||||
34
vendor/cxx/tools/buck/prelude/apple/apple_resource_types.bzl
vendored
Normal file
34
vendor/cxx/tools/buck/prelude/apple/apple_resource_types.bzl
vendored
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
# Represents the values for the `destination` field of `apple_resource`
|
||||
AppleResourceDestination = enum(
|
||||
"resources",
|
||||
"frameworks",
|
||||
"executables",
|
||||
"plugins",
|
||||
"xpcservices",
|
||||
)
|
||||
|
||||
# Defines _where_ resources need to be placed in an `apple_bundle`
|
||||
AppleResourceSpec = record(
|
||||
files = field(["artifact"], []),
|
||||
dirs = field(["artifact"], []),
|
||||
content_dirs = field(["artifact"], []),
|
||||
destination = AppleResourceDestination.type,
|
||||
variant_files = field(["artifact"], []),
|
||||
# Map from locale to list of files for that locale, e.g.
|
||||
# `{ "ru.lproj" : ["Localizable.strings"] }`
|
||||
named_variant_files = field({str.type: ["artifact"]}, {}),
|
||||
codesign_files_on_copy = field(bool.type, False),
|
||||
)
|
||||
|
||||
# Used when invoking `ibtool`, `actool` and `momc`
|
||||
AppleResourceProcessingOptions = record(
|
||||
prefer_local = field(bool.type, False),
|
||||
allow_cache_upload = field(bool.type, False),
|
||||
)
|
||||
15
vendor/cxx/tools/buck/prelude/apple/apple_resource_utility.bzl
vendored
Normal file
15
vendor/cxx/tools/buck/prelude/apple/apple_resource_utility.bzl
vendored
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load(":apple_bundle_destination.bzl", "AppleBundleDestination")
|
||||
load(
|
||||
":apple_resource_types.bzl",
|
||||
"AppleResourceDestination", # @unused Used as a type
|
||||
)
|
||||
|
||||
def apple_bundle_destination_from_resource_destination(res_destination: AppleResourceDestination.type) -> AppleBundleDestination.type:
|
||||
return AppleBundleDestination(res_destination.value)
|
||||
190
vendor/cxx/tools/buck/prelude/apple/apple_rules_impl.bzl
vendored
Normal file
190
vendor/cxx/tools/buck/prelude/apple/apple_rules_impl.bzl
vendored
Normal file
|
|
@ -0,0 +1,190 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load("@prelude//:attributes.bzl", "LinkableDepType", "Linkage")
|
||||
load("@prelude//cxx:headers.bzl", "CPrecompiledHeaderInfo")
|
||||
load("@prelude//cxx:omnibus.bzl", "omnibus_environment_attr")
|
||||
load("@prelude//cxx/user:link_group_map.bzl", "link_group_map_attr")
|
||||
load(":apple_asset_catalog.bzl", "apple_asset_catalog_impl")
|
||||
load(":apple_binary.bzl", "apple_binary_impl")
|
||||
load(":apple_bundle.bzl", "apple_bundle_impl")
|
||||
load(":apple_code_signing_types.bzl", "CodeSignType")
|
||||
load(":apple_core_data.bzl", "apple_core_data_impl")
|
||||
load(":apple_library.bzl", "apple_library_impl")
|
||||
load(":apple_package.bzl", "apple_package_impl")
|
||||
load(":apple_resource.bzl", "apple_resource_impl")
|
||||
load(
|
||||
":apple_rules_impl_utility.bzl",
|
||||
"APPLE_ARCHIVE_OBJECTS_LOCALLY_OVERRIDE_ATTR_NAME",
|
||||
"APPLE_LINK_BINARIES_LOCALLY_OVERRIDE_ATTR_NAME",
|
||||
"APPLE_LINK_LIBRARIES_LOCALLY_OVERRIDE_ATTR_NAME",
|
||||
"apple_bundle_extra_attrs",
|
||||
"get_apple_toolchain_attr",
|
||||
"get_apple_xctoolchain_attr",
|
||||
"get_apple_xctoolchain_bundle_id_attr",
|
||||
)
|
||||
load(":apple_test.bzl", "apple_test_impl")
|
||||
load(":apple_toolchain.bzl", "apple_toolchain_impl")
|
||||
load(":apple_toolchain_types.bzl", "AppleToolsInfo")
|
||||
load(":prebuilt_apple_framework.bzl", "prebuilt_apple_framework_impl")
|
||||
load(":swift_toolchain.bzl", "swift_toolchain_impl")
|
||||
load(":xcode_postbuild_script.bzl", "xcode_postbuild_script_impl")
|
||||
load(":xcode_prebuild_script.bzl", "xcode_prebuild_script_impl")
|
||||
|
||||
implemented_rules = {
|
||||
"apple_asset_catalog": apple_asset_catalog_impl,
|
||||
"apple_binary": apple_binary_impl,
|
||||
"apple_bundle": apple_bundle_impl,
|
||||
"apple_library": apple_library_impl,
|
||||
"apple_package": apple_package_impl,
|
||||
"apple_resource": apple_resource_impl,
|
||||
"apple_test": apple_test_impl,
|
||||
"apple_toolchain": apple_toolchain_impl,
|
||||
"core_data_model": apple_core_data_impl,
|
||||
"prebuilt_apple_framework": prebuilt_apple_framework_impl,
|
||||
"swift_toolchain": swift_toolchain_impl,
|
||||
"xcode_postbuild_script": xcode_postbuild_script_impl,
|
||||
"xcode_prebuild_script": xcode_prebuild_script_impl,
|
||||
}
|
||||
|
||||
extra_attributes = {
|
||||
"apple_asset_catalog": {
|
||||
"dirs": attrs.list(attrs.source(allow_directory = True), default = []),
|
||||
},
|
||||
"apple_binary": {
|
||||
"binary_linker_flags": attrs.list(attrs.arg(), default = []),
|
||||
"enable_distributed_thinlto": attrs.bool(default = False),
|
||||
"extra_xcode_sources": attrs.list(attrs.source(allow_directory = True), default = []),
|
||||
"link_group_map": link_group_map_attr(),
|
||||
"link_postprocessor": attrs.option(attrs.exec_dep(), default = None),
|
||||
"precompiled_header": attrs.option(attrs.dep(providers = [CPrecompiledHeaderInfo]), default = None),
|
||||
"prefer_stripped_objects": attrs.bool(default = False),
|
||||
"preferred_linkage": attrs.enum(Linkage, default = "any"),
|
||||
"stripped": attrs.bool(default = False),
|
||||
"_apple_toolchain": get_apple_toolchain_attr(),
|
||||
"_apple_xctoolchain": get_apple_xctoolchain_attr(),
|
||||
"_apple_xctoolchain_bundle_id": get_apple_xctoolchain_bundle_id_attr(),
|
||||
"_omnibus_environment": omnibus_environment_attr(),
|
||||
APPLE_LINK_BINARIES_LOCALLY_OVERRIDE_ATTR_NAME: attrs.option(attrs.bool(), default = None),
|
||||
},
|
||||
"apple_bundle": apple_bundle_extra_attrs(),
|
||||
"apple_library": {
|
||||
"extra_xcode_sources": attrs.list(attrs.source(allow_directory = True), default = []),
|
||||
"link_group_map": link_group_map_attr(),
|
||||
"link_postprocessor": attrs.option(attrs.exec_dep(), default = None),
|
||||
"precompiled_header": attrs.option(attrs.dep(providers = [CPrecompiledHeaderInfo]), default = None),
|
||||
"preferred_linkage": attrs.enum(Linkage, default = "any"),
|
||||
"serialize_debugging_options": attrs.bool(default = True),
|
||||
"stripped": attrs.bool(default = False),
|
||||
"use_archive": attrs.option(attrs.bool(), default = None),
|
||||
"_apple_toolchain": get_apple_toolchain_attr(),
|
||||
# FIXME: prelude// should be standalone (not refer to fbsource//)
|
||||
"_apple_tools": attrs.exec_dep(default = "fbsource//xplat/buck2/platform/apple:apple-tools", providers = [AppleToolsInfo]),
|
||||
"_apple_xctoolchain": get_apple_xctoolchain_attr(),
|
||||
"_apple_xctoolchain_bundle_id": get_apple_xctoolchain_bundle_id_attr(),
|
||||
"_omnibus_environment": omnibus_environment_attr(),
|
||||
APPLE_LINK_LIBRARIES_LOCALLY_OVERRIDE_ATTR_NAME: attrs.option(attrs.bool(), default = None),
|
||||
APPLE_ARCHIVE_OBJECTS_LOCALLY_OVERRIDE_ATTR_NAME: attrs.option(attrs.bool(), default = None),
|
||||
},
|
||||
"apple_resource": {
|
||||
"codesign_on_copy": attrs.bool(default = False),
|
||||
"content_dirs": attrs.list(attrs.source(allow_directory = True), default = []),
|
||||
"dirs": attrs.list(attrs.source(allow_directory = True), default = []),
|
||||
},
|
||||
# To build an `apple_test`, one needs to first build a shared `apple_library` then
|
||||
# wrap this test library into an `apple_bundle`. Because of this, `apple_test` has attributes
|
||||
# from both `apple_library` and `apple_bundle`.
|
||||
"apple_test": {
|
||||
# Expected by `apple_bundle`, for `apple_test` this field is always None.
|
||||
"binary": attrs.option(attrs.dep(), default = None),
|
||||
# The resulting test bundle should have .xctest extension.
|
||||
"extension": attrs.string(default = "xctest"),
|
||||
"extra_xcode_sources": attrs.list(attrs.source(allow_directory = True), default = []),
|
||||
"link_postprocessor": attrs.option(attrs.exec_dep(), default = None),
|
||||
# Used to create the shared test library. Any library deps whose `preferred_linkage` isn't "shared" will
|
||||
# be treated as "static" deps and linked into the shared test library.
|
||||
"link_style": attrs.enum(LinkableDepType, default = "static"),
|
||||
# The test source code and lib dependencies should be built into a shared library.
|
||||
"preferred_linkage": attrs.enum(Linkage, default = "shared"),
|
||||
# Expected by `apple_bundle`, for `apple_test` this field is always None.
|
||||
"resource_group": attrs.option(attrs.string(), default = None),
|
||||
# Expected by `apple_bundle`, for `apple_test` this field is always None.
|
||||
"resource_group_map": attrs.option(attrs.string(), default = None),
|
||||
"stripped": attrs.bool(default = False),
|
||||
"_apple_toolchain": get_apple_toolchain_attr(),
|
||||
# FIXME: prelude// should be standalone (not refer to fbsource//)
|
||||
"_apple_tools": attrs.exec_dep(default = "fbsource//xplat/buck2/platform/apple:apple-tools", providers = [AppleToolsInfo]),
|
||||
"_apple_xctoolchain": get_apple_xctoolchain_attr(),
|
||||
"_apple_xctoolchain_bundle_id": get_apple_xctoolchain_bundle_id_attr(),
|
||||
"_codesign_type": attrs.option(attrs.enum(CodeSignType.values()), default = None),
|
||||
"_compile_resources_locally_override": attrs.option(attrs.bool(), default = None),
|
||||
"_incremental_bundling_enabled": attrs.bool(default = False),
|
||||
"_omnibus_environment": omnibus_environment_attr(),
|
||||
"_profile_bundling_enabled": attrs.bool(default = False),
|
||||
APPLE_LINK_LIBRARIES_LOCALLY_OVERRIDE_ATTR_NAME: attrs.option(attrs.bool(), default = None),
|
||||
},
|
||||
"apple_toolchain": {
|
||||
# The Buck v1 attribute specs defines those as `attrs.source()` but
|
||||
# we want to properly handle any runnable tools that might have
|
||||
# addition runtime requirements.
|
||||
"actool": attrs.dep(providers = [RunInfo]),
|
||||
"codesign": attrs.dep(providers = [RunInfo]),
|
||||
"codesign_allocate": attrs.dep(providers = [RunInfo]),
|
||||
"codesign_identities_command": attrs.option(attrs.dep(providers = [RunInfo]), default = None),
|
||||
# Controls invocations of `ibtool`, `actool` and `momc`
|
||||
"compile_resources_locally": attrs.bool(default = False),
|
||||
"dsymutil": attrs.dep(providers = [RunInfo]),
|
||||
"dwarfdump": attrs.option(attrs.dep(providers = [RunInfo]), default = None),
|
||||
"ibtool": attrs.dep(providers = [RunInfo]),
|
||||
"libtool": attrs.dep(providers = [RunInfo]),
|
||||
"lipo": attrs.dep(providers = [RunInfo]),
|
||||
"min_version": attrs.option(attrs.string(), default = None),
|
||||
"momc": attrs.dep(providers = [RunInfo]),
|
||||
"platform_path": attrs.option(attrs.source()), # Mark as optional until we remove `_internal_platform_path`
|
||||
"sdk_path": attrs.option(attrs.source()), # Mark as optional until we remove `_internal_sdk_path`
|
||||
"version": attrs.option(attrs.string(), default = None),
|
||||
"xcode_build_version": attrs.option(attrs.string(), default = None),
|
||||
"xcode_version": attrs.option(attrs.string(), default = None),
|
||||
"xctest": attrs.dep(providers = [RunInfo]),
|
||||
# TODO(T111858757): Mirror of `platform_path` but treated as a string. It allows us to
|
||||
# pass abs paths during development and using the currently selected Xcode.
|
||||
"_internal_platform_path": attrs.option(attrs.string()),
|
||||
# TODO(T111858757): Mirror of `sdk_path` but treated as a string. It allows us to
|
||||
# pass abs paths during development and using the currently selected Xcode.
|
||||
"_internal_sdk_path": attrs.option(attrs.string()),
|
||||
},
|
||||
"core_data_model": {
|
||||
"path": attrs.source(allow_directory = True),
|
||||
},
|
||||
"prebuilt_apple_framework": {
|
||||
"framework": attrs.option(attrs.source(allow_directory = True), default = None),
|
||||
"preferred_linkage": attrs.enum(Linkage, default = "any"),
|
||||
"_apple_toolchain": get_apple_toolchain_attr(),
|
||||
"_omnibus_environment": omnibus_environment_attr(),
|
||||
},
|
||||
"scene_kit_assets": {
|
||||
"path": attrs.source(allow_directory = True),
|
||||
},
|
||||
"swift_library": {
|
||||
"preferred_linkage": attrs.enum(Linkage, default = "any"),
|
||||
},
|
||||
"swift_toolchain": {
|
||||
"architecture": attrs.option(attrs.string(), default = None), # TODO(T115173356): Make field non-optional
|
||||
"platform_path": attrs.option(attrs.source()), # Mark as optional until we remove `_internal_platform_path`
|
||||
"sdk_modules": attrs.list(attrs.dep(), default = []), # A list or a root target that represent a graph of sdk modules (e.g Frameworks)
|
||||
"sdk_path": attrs.option(attrs.source()), # Mark as optional until we remove `_internal_sdk_path`
|
||||
"swift_stdlib_tool": attrs.exec_dep(providers = [RunInfo]),
|
||||
"swiftc": attrs.exec_dep(providers = [RunInfo]),
|
||||
# TODO(T111858757): Mirror of `platform_path` but treated as a string. It allows us to
|
||||
# pass abs paths during development and using the currently selected Xcode.
|
||||
"_internal_platform_path": attrs.option(attrs.string(), default = None),
|
||||
# TODO(T111858757): Mirror of `sdk_path` but treated as a string. It allows us to
|
||||
# pass abs paths during development and using the currently selected Xcode.
|
||||
"_internal_sdk_path": attrs.option(attrs.string(), default = None),
|
||||
"_swiftc_wrapper": attrs.dep(providers = [RunInfo], default = "prelude//apple/tools:swift_exec"),
|
||||
},
|
||||
}
|
||||
51
vendor/cxx/tools/buck/prelude/apple/apple_rules_impl_utility.bzl
vendored
Normal file
51
vendor/cxx/tools/buck/prelude/apple/apple_rules_impl_utility.bzl
vendored
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load("@prelude//apple:apple_bundle_types.bzl", "AppleBundleResourceInfo")
|
||||
load("@prelude//apple:apple_code_signing_types.bzl", "CodeSignType")
|
||||
load("@prelude//apple:apple_toolchain_types.bzl", "AppleToolchainInfo", "AppleToolsInfo")
|
||||
load("@prelude//apple/user:resource_group_map.bzl", "resource_group_map_attr")
|
||||
|
||||
def get_apple_toolchain_attr():
|
||||
# FIXME: prelude// should be standalone (not refer to fbcode//)
|
||||
return attrs.toolchain_dep(default = "fbcode//buck2/platform/toolchain:apple-default", providers = [AppleToolchainInfo])
|
||||
|
||||
def _get_apple_bundle_toolchain_attr():
|
||||
# FIXME: prelude// should be standalone (not refer to fbcode//)
|
||||
return attrs.toolchain_dep(default = "fbcode//buck2/platform/toolchain:apple-bundle", providers = [AppleToolchainInfo])
|
||||
|
||||
def get_apple_xctoolchain_attr():
|
||||
# FIXME: prelude// should be standalone (not refer to fbcode//)
|
||||
return attrs.toolchain_dep(default = "fbcode//buck2/platform/toolchain:apple-xctoolchain")
|
||||
|
||||
def get_apple_xctoolchain_bundle_id_attr():
|
||||
# FIXME: prelude// should be standalone (not refer to fbcode//)
|
||||
return attrs.toolchain_dep(default = "fbcode//buck2/platform/toolchain:apple-xctoolchain-bundle-id")
|
||||
|
||||
APPLE_LINK_BINARIES_LOCALLY_OVERRIDE_ATTR_NAME = "_link_binaries_locally_override"
|
||||
APPLE_LINK_LIBRARIES_LOCALLY_OVERRIDE_ATTR_NAME = "_link_libraries_locally_override"
|
||||
APPLE_ARCHIVE_OBJECTS_LOCALLY_OVERRIDE_ATTR_NAME = "_archive_objects_locally_override"
|
||||
|
||||
def apple_bundle_extra_attrs():
|
||||
return {
|
||||
"resource_group_map": resource_group_map_attr(),
|
||||
# FIXME: prelude// should be standalone (not refer to buck//)
|
||||
"_apple_installer": attrs.label(default = "buck//src/com/facebook/buck/installer/apple:apple_installer"),
|
||||
"_apple_toolchain": _get_apple_bundle_toolchain_attr(),
|
||||
# FIXME: prelude// should be standalone (not refer to fbsource//)
|
||||
"_apple_tools": attrs.exec_dep(default = "fbsource//xplat/buck2/platform/apple:apple-tools", providers = [AppleToolsInfo]),
|
||||
"_apple_xctoolchain": get_apple_xctoolchain_attr(),
|
||||
"_apple_xctoolchain_bundle_id": get_apple_xctoolchain_bundle_id_attr(),
|
||||
"_codesign_entitlements": attrs.option(attrs.source(), default = None),
|
||||
"_codesign_type": attrs.option(attrs.enum(CodeSignType.values()), default = None),
|
||||
"_compile_resources_locally_override": attrs.option(attrs.bool(), default = None),
|
||||
"_incremental_bundling_enabled": attrs.bool(default = False),
|
||||
"_profile_bundling_enabled": attrs.bool(default = False),
|
||||
# FIXME: prelude// should be standalone (not refer to fbsource//)
|
||||
"_provisioning_profiles": attrs.dep(default = "fbsource//xplat/buck2/platform/apple:provisioning_profiles"),
|
||||
"_resource_bundle": attrs.option(attrs.dep(providers = [AppleBundleResourceInfo]), default = None),
|
||||
}
|
||||
15
vendor/cxx/tools/buck/prelude/apple/apple_sdk.bzl
vendored
Normal file
15
vendor/cxx/tools/buck/prelude/apple/apple_sdk.bzl
vendored
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load("@prelude//apple:apple_toolchain_types.bzl", "AppleToolchainInfo")
|
||||
|
||||
def get_apple_sdk_name(ctx: "context") -> str.type:
|
||||
"""
|
||||
Get the SDK defined on the toolchain.
|
||||
Will throw if the `_apple_toolchain` is not present.
|
||||
"""
|
||||
return ctx.attrs._apple_toolchain[AppleToolchainInfo].sdk_name
|
||||
39
vendor/cxx/tools/buck/prelude/apple/apple_sdk_clang_module.bzl
vendored
Normal file
39
vendor/cxx/tools/buck/prelude/apple/apple_sdk_clang_module.bzl
vendored
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load(":swift_pcm_compilation.bzl", "get_shared_pcm_compilation_args")
|
||||
load(":swift_toolchain_types.bzl", "SdkUncompiledModuleInfo")
|
||||
|
||||
def apple_sdk_clang_module_impl(ctx: "context") -> ["provider"]:
|
||||
cmd = get_shared_pcm_compilation_args(ctx.attrs.target, ctx.attrs.module_name)
|
||||
module_dependency_infos = filter(None, [d.get(SdkUncompiledModuleInfo) for d in ctx.attrs.deps])
|
||||
return [
|
||||
DefaultInfo(),
|
||||
SdkUncompiledModuleInfo(
|
||||
name = ctx.attrs.name,
|
||||
module_name = ctx.attrs.module_name,
|
||||
is_framework = ctx.attrs.is_framework,
|
||||
is_swiftmodule = False,
|
||||
partial_cmd = cmd,
|
||||
input_relative_path = ctx.attrs.modulemap_relative_path,
|
||||
deps = module_dependency_infos,
|
||||
),
|
||||
]
|
||||
|
||||
# This rule represent a Clang module from SDK and forms a graph of dependencies between such modules.
|
||||
apple_sdk_clang_module = rule(
|
||||
impl = apple_sdk_clang_module_impl,
|
||||
attrs = {
|
||||
"deps": attrs.list(attrs.dep(), default = []),
|
||||
"is_framework": attrs.bool(default = False),
|
||||
# This is a real module name, contrary to `name`
|
||||
# which has a special suffix to distinguish Swift and Clang modules with the same name
|
||||
"module_name": attrs.string(),
|
||||
"modulemap_relative_path": attrs.string(),
|
||||
"target": attrs.string(),
|
||||
},
|
||||
)
|
||||
95
vendor/cxx/tools/buck/prelude/apple/apple_sdk_metadata.bzl
vendored
Normal file
95
vendor/cxx/tools/buck/prelude/apple/apple_sdk_metadata.bzl
vendored
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
AppleSdkMetadata = record(
|
||||
name = field(str.type),
|
||||
target_device_flags = field([str.type], []),
|
||||
is_ad_hoc_code_sign_sufficient = field(bool.type),
|
||||
info_plist_supported_platforms_values = field([str.type]),
|
||||
min_version_plist_info_key = field(str.type),
|
||||
)
|
||||
|
||||
IPhoneOSSdkMetadata = AppleSdkMetadata(
|
||||
name = "iphoneos",
|
||||
target_device_flags = ["--target-device", "iphone", "--target-device", "ipad"],
|
||||
is_ad_hoc_code_sign_sufficient = False,
|
||||
info_plist_supported_platforms_values = ["iPhoneOS"],
|
||||
min_version_plist_info_key = "MinimumOSVersion",
|
||||
)
|
||||
|
||||
IPhoneSimulatorSdkMetadata = AppleSdkMetadata(
|
||||
name = "iphonesimulator",
|
||||
target_device_flags = ["--target-device", "iphone", "--target-device", "ipad"],
|
||||
is_ad_hoc_code_sign_sufficient = True,
|
||||
info_plist_supported_platforms_values = ["iPhoneSimulator"],
|
||||
min_version_plist_info_key = "MinimumOSVersion",
|
||||
)
|
||||
|
||||
TVOSSdkMetadata = AppleSdkMetadata(
|
||||
name = "appletvos",
|
||||
target_device_flags = ["--target-device", "tv"],
|
||||
is_ad_hoc_code_sign_sufficient = False,
|
||||
info_plist_supported_platforms_values = ["AppleTVOS"],
|
||||
min_version_plist_info_key = "MinimumOSVersion",
|
||||
)
|
||||
|
||||
TVSimulatorSdkMetadata = AppleSdkMetadata(
|
||||
name = "appletvsimulator",
|
||||
target_device_flags = ["--target-device", "tv"],
|
||||
is_ad_hoc_code_sign_sufficient = True,
|
||||
info_plist_supported_platforms_values = ["AppleTVSimulator"],
|
||||
min_version_plist_info_key = "MinimumOSVersion",
|
||||
)
|
||||
|
||||
WatchOSSdkMetadata = AppleSdkMetadata(
|
||||
name = "watchos",
|
||||
target_device_flags = ["--target-device", "watch"],
|
||||
is_ad_hoc_code_sign_sufficient = False,
|
||||
info_plist_supported_platforms_values = ["WatchOS"],
|
||||
min_version_plist_info_key = "MinimumOSVersion",
|
||||
)
|
||||
|
||||
WatchSimulatorSdkMetadata = AppleSdkMetadata(
|
||||
name = "watchsimulator",
|
||||
target_device_flags = ["--target-device", "watch"],
|
||||
is_ad_hoc_code_sign_sufficient = True,
|
||||
info_plist_supported_platforms_values = ["WatchSimulator"],
|
||||
min_version_plist_info_key = "MinimumOSVersion",
|
||||
)
|
||||
|
||||
MacOSXSdkMetadata = AppleSdkMetadata(
|
||||
name = "macosx",
|
||||
target_device_flags = ["--target-device", "mac"],
|
||||
is_ad_hoc_code_sign_sufficient = True,
|
||||
info_plist_supported_platforms_values = ["MacOSX"],
|
||||
min_version_plist_info_key = "LSMinimumSystemVersion",
|
||||
)
|
||||
|
||||
MacOSXCatalystSdkMetadata = AppleSdkMetadata(
|
||||
name = "maccatalyst",
|
||||
target_device_flags = ["--target-device", "ipad"],
|
||||
is_ad_hoc_code_sign_sufficient = True,
|
||||
info_plist_supported_platforms_values = ["MacOSX"],
|
||||
min_version_plist_info_key = "LSMinimumSystemVersion",
|
||||
)
|
||||
|
||||
_SDK_MAP = {
|
||||
IPhoneOSSdkMetadata.name: IPhoneOSSdkMetadata,
|
||||
IPhoneSimulatorSdkMetadata.name: IPhoneSimulatorSdkMetadata,
|
||||
TVOSSdkMetadata.name: TVOSSdkMetadata,
|
||||
TVSimulatorSdkMetadata.name: TVSimulatorSdkMetadata,
|
||||
WatchOSSdkMetadata.name: WatchOSSdkMetadata,
|
||||
WatchSimulatorSdkMetadata.name: WatchSimulatorSdkMetadata,
|
||||
MacOSXSdkMetadata.name: MacOSXSdkMetadata,
|
||||
MacOSXCatalystSdkMetadata.name: MacOSXCatalystSdkMetadata,
|
||||
}
|
||||
|
||||
def get_apple_sdk_metadata_for_sdk_name(name: str.type) -> AppleSdkMetadata.type:
|
||||
sdk = _SDK_MAP.get(name)
|
||||
if sdk == None:
|
||||
fail("unrecognized sdk name: `{}`".format(name))
|
||||
return sdk
|
||||
45
vendor/cxx/tools/buck/prelude/apple/apple_sdk_module.bzl
vendored
Normal file
45
vendor/cxx/tools/buck/prelude/apple/apple_sdk_module.bzl
vendored
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load(":apple_sdk_modules_utility.bzl", "SDKDepTSet")
|
||||
load(":apple_sdk_swift_module.bzl", "compile_sdk_swiftinterface")
|
||||
load(":swift_pcm_compilation.bzl", "compile_swift_sdk_pcm")
|
||||
|
||||
# Starting from a root node, this helper function traverses a graph of uncompiled SDK modules
|
||||
# to create a graph of compiled ones.
|
||||
def create_sdk_modules_graph(
|
||||
ctx: "context",
|
||||
sdk_module_providers: {str.type: "SdkCompiledModuleInfo"},
|
||||
uncompiled_sdk_module_info: "SdkUncompiledModuleInfo",
|
||||
toolchain_context: struct.type):
|
||||
# If input_relative_path is None then this module represents a root node of SDK modules graph.
|
||||
# In such case, we need to handle only its deps.
|
||||
if uncompiled_sdk_module_info.input_relative_path == None:
|
||||
for uncompiled_dependency_info in uncompiled_sdk_module_info.deps:
|
||||
create_sdk_modules_graph(ctx, sdk_module_providers, uncompiled_dependency_info, toolchain_context)
|
||||
return
|
||||
|
||||
# If provider is already created, return.
|
||||
if uncompiled_sdk_module_info.name in sdk_module_providers:
|
||||
return
|
||||
|
||||
compiled_dependency_infos_tsets = []
|
||||
for uncompiled_dependency_info in uncompiled_sdk_module_info.deps:
|
||||
create_sdk_modules_graph(ctx, sdk_module_providers, uncompiled_dependency_info, toolchain_context)
|
||||
compiled_dependency_info = sdk_module_providers[uncompiled_dependency_info.name]
|
||||
sdk_dep_tset = ctx.actions.tset(
|
||||
SDKDepTSet,
|
||||
value = compiled_dependency_info,
|
||||
children = [compiled_dependency_info.deps],
|
||||
)
|
||||
compiled_dependency_infos_tsets.append(sdk_dep_tset)
|
||||
|
||||
sdk_deps_set = ctx.actions.tset(SDKDepTSet, children = compiled_dependency_infos_tsets)
|
||||
if uncompiled_sdk_module_info.is_swiftmodule:
|
||||
compile_sdk_swiftinterface(ctx, toolchain_context, sdk_deps_set, uncompiled_sdk_module_info, sdk_module_providers)
|
||||
else:
|
||||
compile_swift_sdk_pcm(ctx, toolchain_context, sdk_deps_set, uncompiled_sdk_module_info, sdk_module_providers)
|
||||
67
vendor/cxx/tools/buck/prelude/apple/apple_sdk_modules_utility.bzl
vendored
Normal file
67
vendor/cxx/tools/buck/prelude/apple/apple_sdk_modules_utility.bzl
vendored
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load(":swift_pcm_compilation_types.bzl", "SwiftPCMCompilationInfo")
|
||||
|
||||
def project_as_hidden(module_info: "SdkCompiledModuleInfo"):
|
||||
# NOTE(cjhopman): This would probably be better done by projecting as normal args and the caller putting it in hidden.
|
||||
args = cmd_args()
|
||||
args.hidden(module_info.output_artifact)
|
||||
return args
|
||||
|
||||
def project_as_clang_deps(module_info: "SdkCompiledModuleInfo"):
|
||||
if module_info.is_swiftmodule:
|
||||
return []
|
||||
else:
|
||||
return [
|
||||
"-Xcc",
|
||||
cmd_args(["-fmodule-file=", module_info.module_name, "=", module_info.output_artifact], delimiter = ""),
|
||||
"-Xcc",
|
||||
cmd_args(["-fmodule-map-file=", module_info.input_relative_path], delimiter = ""),
|
||||
]
|
||||
|
||||
SDKDepTSet = transitive_set(args_projections = {
|
||||
"clang_deps": project_as_clang_deps,
|
||||
"hidden": project_as_hidden,
|
||||
})
|
||||
|
||||
def is_sdk_modules_provided(toolchain: "SwiftToolchainInfo") -> bool.type:
|
||||
no_swift_modules = toolchain.compiled_sdk_swift_modules == None or len(toolchain.compiled_sdk_swift_modules) == 0
|
||||
no_clang_modules = toolchain.compiled_sdk_clang_modules == None or len(toolchain.compiled_sdk_clang_modules) == 0
|
||||
if no_swift_modules and no_clang_modules:
|
||||
return False
|
||||
return True
|
||||
|
||||
def get_sdk_deps_tset(
|
||||
ctx: "context",
|
||||
module_name: str.type,
|
||||
deps: ["dependency"],
|
||||
required_modules: [str.type],
|
||||
toolchain: "SwiftToolchainInfo") -> "SDKDepTSet":
|
||||
if not is_sdk_modules_provided(toolchain):
|
||||
fail("SDK deps are not set for swift_toolchain")
|
||||
|
||||
all_sdk_deps = [
|
||||
d[SwiftPCMCompilationInfo].sdk_deps_set
|
||||
for d in deps
|
||||
if SwiftPCMCompilationInfo in d
|
||||
]
|
||||
|
||||
# Adding all direct and transitive SDK dependencies.
|
||||
for sdk_module_dep_name in ctx.attrs.sdk_modules + required_modules:
|
||||
if sdk_module_dep_name not in toolchain.compiled_sdk_swift_modules and sdk_module_dep_name not in toolchain.compiled_sdk_clang_modules:
|
||||
fail("{} depends on a non-existing SDK module: {}".format(module_name, sdk_module_dep_name))
|
||||
|
||||
sdk_compiled_module_info = toolchain.compiled_sdk_swift_modules.get(sdk_module_dep_name) or toolchain.compiled_sdk_clang_modules.get(sdk_module_dep_name)
|
||||
sdk_module_with_transitive_deps_tset = ctx.actions.tset(
|
||||
SDKDepTSet,
|
||||
value = sdk_compiled_module_info,
|
||||
children = [sdk_compiled_module_info.deps],
|
||||
)
|
||||
all_sdk_deps.append(sdk_module_with_transitive_deps_tset)
|
||||
|
||||
return ctx.actions.tset(SDKDepTSet, children = all_sdk_deps)
|
||||
118
vendor/cxx/tools/buck/prelude/apple/apple_sdk_swift_module.bzl
vendored
Normal file
118
vendor/cxx/tools/buck/prelude/apple/apple_sdk_swift_module.bzl
vendored
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load(":apple_utility.bzl", "expand_relative_prefixed_sdk_path", "get_disable_pch_validation_flags")
|
||||
load(":swift_module_map.bzl", "write_swift_module_map")
|
||||
load(":swift_toolchain_types.bzl", "SdkCompiledModuleInfo", "SdkUncompiledModuleInfo")
|
||||
|
||||
def compile_sdk_swiftinterface(
|
||||
ctx: "context",
|
||||
toolchain_context: struct.type,
|
||||
sdk_deps_set: "SDKDepTSet",
|
||||
uncompiled_sdk_module_info: "SdkUncompiledModuleInfo",
|
||||
sdk_module_providers: {str.type: "SdkCompiledModuleInfo"}):
|
||||
uncompiled_module_info_name = uncompiled_sdk_module_info.module_name
|
||||
|
||||
cmd = cmd_args(toolchain_context.compiler)
|
||||
cmd.add(uncompiled_sdk_module_info.partial_cmd)
|
||||
cmd.add(["-sdk", toolchain_context.sdk_path])
|
||||
cmd.add(toolchain_context.compiler_flags)
|
||||
|
||||
if toolchain_context.swift_resource_dir:
|
||||
cmd.add([
|
||||
"-resource-dir",
|
||||
toolchain_context.swift_resource_dir,
|
||||
])
|
||||
|
||||
swift_module_map_artifact = write_swift_module_map(ctx, uncompiled_module_info_name, list(sdk_deps_set.traverse()))
|
||||
cmd.add([
|
||||
"-explicit-swift-module-map-file",
|
||||
swift_module_map_artifact,
|
||||
])
|
||||
|
||||
# sdk_swiftinterface_compile should explicitly depend on its deps that go to swift_modulemap
|
||||
cmd.hidden(sdk_deps_set.project_as_args("hidden"))
|
||||
cmd.add(sdk_deps_set.project_as_args("clang_deps"))
|
||||
|
||||
swiftmodule_output = ctx.actions.declare_output(uncompiled_module_info_name + ".swiftmodule")
|
||||
expanded_swiftinterface_cmd = expand_relative_prefixed_sdk_path(
|
||||
cmd_args(toolchain_context.sdk_path),
|
||||
cmd_args(toolchain_context.swift_resource_dir),
|
||||
uncompiled_sdk_module_info.input_relative_path,
|
||||
)
|
||||
cmd.add([
|
||||
"-o",
|
||||
swiftmodule_output.as_output(),
|
||||
expanded_swiftinterface_cmd,
|
||||
])
|
||||
|
||||
sdk_module_providers[uncompiled_sdk_module_info.name] = SdkCompiledModuleInfo(
|
||||
name = uncompiled_sdk_module_info.name,
|
||||
module_name = uncompiled_module_info_name,
|
||||
is_framework = uncompiled_sdk_module_info.is_framework,
|
||||
is_swiftmodule = True,
|
||||
output_artifact = swiftmodule_output,
|
||||
deps = sdk_deps_set,
|
||||
input_relative_path = expanded_swiftinterface_cmd,
|
||||
)
|
||||
|
||||
ctx.actions.run(cmd, category = "sdk_swiftinterface_compile", identifier = uncompiled_module_info_name)
|
||||
|
||||
def apple_sdk_swift_module_impl(ctx: "context") -> ["provider"]:
|
||||
module_name = ctx.attrs.module_name
|
||||
|
||||
cmd = cmd_args([
|
||||
"-frontend",
|
||||
"-compile-module-from-interface",
|
||||
"-disable-implicit-swift-modules",
|
||||
"-serialize-parseable-module-interface-dependency-hashes",
|
||||
"-disable-modules-validate-system-headers",
|
||||
"-suppress-warnings",
|
||||
"-module-name",
|
||||
module_name,
|
||||
"-target",
|
||||
ctx.attrs.target,
|
||||
"-Xcc",
|
||||
"-fno-implicit-modules",
|
||||
"-Xcc",
|
||||
"-fno-implicit-module-maps",
|
||||
])
|
||||
cmd.add(get_disable_pch_validation_flags())
|
||||
|
||||
if module_name == "Swift" or module_name == "SwiftOnoneSupport":
|
||||
cmd.add([
|
||||
"-parse-stdlib",
|
||||
])
|
||||
|
||||
module_dependency_infos = filter(None, [d.get(SdkUncompiledModuleInfo) for d in ctx.attrs.deps])
|
||||
return [
|
||||
DefaultInfo(),
|
||||
SdkUncompiledModuleInfo(
|
||||
name = ctx.attrs.name,
|
||||
module_name = ctx.attrs.module_name,
|
||||
is_framework = ctx.attrs.is_framework,
|
||||
is_swiftmodule = True,
|
||||
partial_cmd = cmd,
|
||||
input_relative_path = ctx.attrs.swiftinterface_relative_path,
|
||||
deps = module_dependency_infos,
|
||||
),
|
||||
]
|
||||
|
||||
# This rule represent a Swift module from SDK and forms a graph of dependencies between such modules.
|
||||
apple_sdk_swift_module = rule(
|
||||
impl = apple_sdk_swift_module_impl,
|
||||
attrs = {
|
||||
"deps": attrs.list(attrs.dep(), default = []),
|
||||
"is_framework": attrs.bool(default = False),
|
||||
# This is a real module name, contrary to `name`
|
||||
# which has a special suffix to distinguish Swift and Clang modules with the same name
|
||||
"module_name": attrs.string(),
|
||||
# A prefixed path ($SDKROOT/$PLATFORM_DIR) to swiftinterface textual file.
|
||||
"swiftinterface_relative_path": attrs.option(attrs.string(), default = None), # if `swiftinterface` is None represents a Root node.
|
||||
"target": attrs.string(),
|
||||
},
|
||||
)
|
||||
13
vendor/cxx/tools/buck/prelude/apple/apple_stripping.bzl
vendored
Normal file
13
vendor/cxx/tools/buck/prelude/apple/apple_stripping.bzl
vendored
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load("@prelude//cxx:cxx_context.bzl", "get_cxx_toolchain_info")
|
||||
|
||||
def apple_strip_args(ctx: "context") -> "cmd_args":
|
||||
cxx_toolchain_info = get_cxx_toolchain_info(ctx)
|
||||
flags = cxx_toolchain_info.strip_flags_info.strip_non_global_flags
|
||||
return cmd_args(flags) if flags != None else cmd_args(["-x", "-T"])
|
||||
79
vendor/cxx/tools/buck/prelude/apple/apple_target_sdk_version.bzl
vendored
Normal file
79
vendor/cxx/tools/buck/prelude/apple/apple_target_sdk_version.bzl
vendored
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load("@prelude//apple:apple_toolchain_types.bzl", "AppleToolchainInfo")
|
||||
load("@prelude//cxx:preprocessor.bzl", "CPreprocessor")
|
||||
load(":apple_sdk.bzl", "get_apple_sdk_name")
|
||||
|
||||
# TODO(T112099448): In the future, the min version flag should live on the apple_toolchain()
|
||||
# TODO(T113776898): Switch to -mtargetos= flag which should live on the apple_toolchain()
|
||||
_APPLE_MIN_VERSION_FLAG_SDK_MAP = {
|
||||
"iphoneos": "-mios-version-min",
|
||||
"iphonesimulator": "-mios-simulator-version-min",
|
||||
"macosx": "-mmacosx-version-min",
|
||||
"watchos": "-mwatchos-version-min",
|
||||
"watchsimulator": "-mwatchsimulator-version-min",
|
||||
}
|
||||
|
||||
# Returns the target SDK version for apple_(binary|library) and uses
|
||||
# apple_toolchain() min version as a fallback. This is the central place
|
||||
# where the version for a particular node is defined, no other places
|
||||
# should be accessing `attrs.target_sdk_version` or `attrs.min_version`.
|
||||
def get_min_deployment_version_for_node(ctx: "context") -> [None, str.type]:
|
||||
toolchain_min_version = ctx.attrs._apple_toolchain[AppleToolchainInfo].min_version
|
||||
if toolchain_min_version == "":
|
||||
toolchain_min_version = None
|
||||
return getattr(ctx.attrs, "target_sdk_version", None) or toolchain_min_version
|
||||
|
||||
# Returns the min deployment flag to pass to the compiler + linker
|
||||
def _get_min_deployment_version_target_flag(ctx: "context") -> [None, str.type]:
|
||||
target_sdk_version = get_min_deployment_version_for_node(ctx)
|
||||
if target_sdk_version == None:
|
||||
return None
|
||||
|
||||
sdk_name = get_apple_sdk_name(ctx)
|
||||
min_version_flag = _APPLE_MIN_VERSION_FLAG_SDK_MAP.get(sdk_name)
|
||||
if min_version_flag == None:
|
||||
fail("Could not determine min version flag for SDK {}".format(sdk_name))
|
||||
|
||||
return "{}={}".format(min_version_flag, target_sdk_version)
|
||||
|
||||
# There are two main ways in which we can pass target SDK version:
|
||||
# - versioned target triple
|
||||
# - unversioned target triple + version flag
|
||||
#
|
||||
# A versioned target triple overrides any version flags and requires
|
||||
# additional flags to disable the warning/error (`-Woverriding-t-option`),
|
||||
# so we prefer to use an unversioned target triple + version flag.
|
||||
#
|
||||
# Furthermore, we want to ensure that there's _exactly one_ version flag
|
||||
# on a compiler/link line. This makes debugging easier and avoids issues
|
||||
# with multiple layers each adding/overriding target SDK. It also makes
|
||||
# it easier to switch to versioned target triple.
|
||||
#
|
||||
# There are exactly two ways in which to specify the target SDK:
|
||||
# - apple_toolchain.min_version sets the default value
|
||||
# - apple_(binary|library).target_sdk_version sets the per-target value
|
||||
#
|
||||
# apple_toolchain() rules should _never_ add any version flags because
|
||||
# the rule does _not_ know whether a particular target will request a
|
||||
# non-default value. Otherwise, we end up with multiple version flags,
|
||||
# one added by the toolchain and then additional overrides by targets.
|
||||
|
||||
def get_min_deployment_version_target_linker_flags(ctx: "context") -> [str.type]:
|
||||
min_version_flag = _get_min_deployment_version_target_flag(ctx)
|
||||
return [min_version_flag] if min_version_flag != None else []
|
||||
|
||||
def get_min_deployment_version_target_preprocessor_flags(ctx: "context") -> [CPreprocessor.type]:
|
||||
min_version_flag = _get_min_deployment_version_target_flag(ctx)
|
||||
if min_version_flag == None:
|
||||
return []
|
||||
|
||||
args = cmd_args(min_version_flag)
|
||||
return [CPreprocessor(
|
||||
args = [args],
|
||||
)]
|
||||
190
vendor/cxx/tools/buck/prelude/apple/apple_test.bzl
vendored
Normal file
190
vendor/cxx/tools/buck/prelude/apple/apple_test.bzl
vendored
Normal file
|
|
@ -0,0 +1,190 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load("@prelude//apple:apple_library.bzl", "AppleLibraryAdditionalParams", "apple_library_rule_constructor_params_and_swift_providers")
|
||||
load("@prelude//apple:apple_toolchain_types.bzl", "AppleToolchainInfo")
|
||||
load(
|
||||
"@prelude//cxx:compile.bzl",
|
||||
"CxxSrcWithFlags", # @unused Used as a type
|
||||
)
|
||||
load("@prelude//cxx:cxx_library.bzl", "cxx_library_parameterized")
|
||||
load("@prelude//cxx:cxx_types.bzl", "CxxRuleProviderParams", "CxxRuleSubTargetParams")
|
||||
load(
|
||||
"@prelude//cxx:linker.bzl",
|
||||
"SharedLibraryFlagOverrides",
|
||||
)
|
||||
load(":apple_bundle.bzl", "AppleBundlePartListConstructorParams", "get_apple_bundle_part_list")
|
||||
load(":apple_bundle_destination.bzl", "AppleBundleDestination")
|
||||
load(":apple_bundle_part.bzl", "AppleBundlePart", "assemble_bundle", "bundle_output")
|
||||
load(":apple_bundle_types.bzl", "AppleBundleInfo")
|
||||
load(":xcode.bzl", "apple_populate_xcode_attributes")
|
||||
|
||||
def apple_test_impl(ctx: "context") -> ["provider"]:
|
||||
xctest_bundle = bundle_output(ctx)
|
||||
|
||||
test_host_app_bundle = _get_test_host_app_bundle(ctx)
|
||||
test_host_app_binary = _get_test_host_app_binary(ctx, test_host_app_bundle)
|
||||
|
||||
objc_bridging_header_flags = [
|
||||
# Disable bridging header -> PCH compilation to mitigate an issue in Xcode 13 beta.
|
||||
"-disable-bridging-pch",
|
||||
"-import-objc-header",
|
||||
cmd_args(ctx.attrs.bridging_header),
|
||||
] if ctx.attrs.bridging_header else []
|
||||
|
||||
constructor_params, _, _ = apple_library_rule_constructor_params_and_swift_providers(
|
||||
ctx,
|
||||
AppleLibraryAdditionalParams(
|
||||
rule_type = "apple_test",
|
||||
extra_exported_link_flags = _get_xctest_framework_linker_flags(ctx) + _get_bundle_loader_flags(test_host_app_binary),
|
||||
extra_swift_compiler_flags = _get_xctest_framework_search_paths_flags(ctx) + objc_bridging_header_flags,
|
||||
shared_library_flags = SharedLibraryFlagOverrides(
|
||||
# When `-bundle` is used we can't use the `-install_name` args, thus we keep this field empty.
|
||||
shared_library_name_linker_flags_format = [],
|
||||
# When building Apple tests, we want to link with `-bundle` instead of `-shared` to allow
|
||||
# linking against the bundle loader.
|
||||
shared_library_flags = ["-bundle"],
|
||||
),
|
||||
generate_sub_targets = CxxRuleSubTargetParams(
|
||||
compilation_database = False,
|
||||
headers = False,
|
||||
link_group_map = False,
|
||||
link_style_outputs = False,
|
||||
),
|
||||
generate_providers = CxxRuleProviderParams(
|
||||
compilation_database = True,
|
||||
default = False,
|
||||
linkable_graph = False,
|
||||
link_style_outputs = False,
|
||||
merged_native_link_info = False,
|
||||
omnibus_root = False,
|
||||
preprocessors = False,
|
||||
resources = False,
|
||||
shared_libraries = False,
|
||||
template_placeholders = False,
|
||||
),
|
||||
populate_xcode_attributes_func = lambda local_ctx, **kwargs: _xcode_populate_attributes(ctx = local_ctx, xctest_bundle = xctest_bundle, test_host_app_binary = test_host_app_binary, **kwargs),
|
||||
# We want to statically link the transitive dep graph of the apple_test()
|
||||
# which we can achieve by forcing link group linking with
|
||||
# an empty mapping (i.e., default mapping).
|
||||
force_link_group_linking = True,
|
||||
),
|
||||
)
|
||||
cxx_library_output = cxx_library_parameterized(ctx, constructor_params)
|
||||
|
||||
binary_part = AppleBundlePart(source = cxx_library_output.default_output.default, destination = AppleBundleDestination("executables"), new_name = ctx.attrs.name)
|
||||
part_list_output = get_apple_bundle_part_list(ctx, AppleBundlePartListConstructorParams(binaries = [binary_part]))
|
||||
assemble_bundle(ctx, xctest_bundle, part_list_output.parts, part_list_output.info_plist_part)
|
||||
|
||||
sub_targets = cxx_library_output.sub_targets
|
||||
|
||||
# If the test has a test host, add a subtarget to build the test host app bundle.
|
||||
sub_targets["test-host"] = [DefaultInfo(default_outputs = [test_host_app_bundle])] if test_host_app_bundle else [DefaultInfo()]
|
||||
|
||||
# When interacting with Tpx, we just pass our various inputs via env vars,
|
||||
# since Tpx basiclaly wants structured output for this.
|
||||
env = {"XCTEST_BUNDLE": xctest_bundle}
|
||||
|
||||
if test_host_app_bundle == None:
|
||||
tpx_label = "tpx:apple_test:buck2:logicTest"
|
||||
else:
|
||||
env["HOST_APP_BUNDLE"] = test_host_app_bundle
|
||||
tpx_label = "tpx:apple_test:buck2:appTest"
|
||||
|
||||
labels = ctx.attrs.labels + [tpx_label]
|
||||
labels.append(tpx_label)
|
||||
|
||||
return [
|
||||
DefaultInfo(default_outputs = [xctest_bundle], sub_targets = sub_targets),
|
||||
ExternalRunnerTestInfo(
|
||||
type = "custom", # We inherit a label via the macro layer that overrides this.
|
||||
command = ["false"], # Tpx makes up its own args, we just pass params via the env.
|
||||
env = env,
|
||||
labels = labels,
|
||||
use_project_relative_paths = True,
|
||||
run_from_project_root = True,
|
||||
contacts = ctx.attrs.contacts,
|
||||
executor_overrides = {
|
||||
"ios-simulator": CommandExecutorConfig(
|
||||
local_enabled = False,
|
||||
remote_enabled = True,
|
||||
remote_execution_properties = {
|
||||
"platform": "ios-simulator-pure-re",
|
||||
"subplatform": "iPhone 8.iOS 15.0",
|
||||
"xcode-version": "xcodestable",
|
||||
},
|
||||
remote_execution_use_case = "tpx-default",
|
||||
),
|
||||
"static-listing": CommandExecutorConfig(local_enabled = True, remote_enabled = False),
|
||||
},
|
||||
),
|
||||
cxx_library_output.xcode_data_info,
|
||||
cxx_library_output.cxx_compilationdb_info,
|
||||
]
|
||||
|
||||
def _get_test_host_app_bundle(ctx: "context") -> ["artifact", None]:
|
||||
""" Get the bundle for the test host app, if one exists for this test. """
|
||||
if ctx.attrs.test_host_app:
|
||||
# Copy the test host app bundle into test's output directory
|
||||
original_bundle = ctx.attrs.test_host_app[AppleBundleInfo].bundle
|
||||
test_host_app_bundle = ctx.actions.declare_output(original_bundle.basename)
|
||||
ctx.actions.copy_file(test_host_app_bundle, original_bundle)
|
||||
return test_host_app_bundle
|
||||
|
||||
return None
|
||||
|
||||
def _get_test_host_app_binary(ctx: "context", test_host_app_bundle: ["artifact", None]) -> ["cmd_args", None]:
|
||||
""" Reference to the binary with the test host app bundle, if one exists for this test. Captures the bundle as an artifact in the cmd_args. """
|
||||
if ctx.attrs.test_host_app:
|
||||
return cmd_args([test_host_app_bundle, ctx.attrs.test_host_app[AppleBundleInfo].binary_name], delimiter = "/")
|
||||
|
||||
return None
|
||||
|
||||
def _get_bundle_loader_flags(binary: ["cmd_args", None]) -> [""]:
|
||||
if binary:
|
||||
# During linking we need to link the test shared lib against the test host binary. The
|
||||
# test host binary doesn't need to be embedded in an `apple_bundle`.
|
||||
return ["-bundle_loader", binary]
|
||||
|
||||
return []
|
||||
|
||||
def _xcode_populate_attributes(
|
||||
ctx,
|
||||
srcs: [CxxSrcWithFlags.type],
|
||||
argsfiles_by_ext: {str.type: "artifact"},
|
||||
xctest_bundle: "artifact",
|
||||
test_host_app_binary: ["cmd_args", None],
|
||||
**_kwargs) -> {str.type: ""}:
|
||||
data = apple_populate_xcode_attributes(ctx = ctx, srcs = srcs, argsfiles_by_ext = argsfiles_by_ext, product_name = ctx.attrs.name)
|
||||
data["output"] = xctest_bundle
|
||||
if test_host_app_binary:
|
||||
data["test_host_app_binary"] = test_host_app_binary
|
||||
return data
|
||||
|
||||
def _get_xctest_framework_search_paths(ctx: "context") -> ("cmd_args", "cmd_args"):
|
||||
toolchain = ctx.attrs._apple_toolchain[AppleToolchainInfo]
|
||||
xctest_swiftmodule_search_path = cmd_args([toolchain.platform_path, "Developer/usr/lib"], delimiter = "/")
|
||||
xctest_framework_search_path = cmd_args([toolchain.platform_path, "Developer/Library/Frameworks"], delimiter = "/")
|
||||
return (xctest_swiftmodule_search_path, xctest_framework_search_path)
|
||||
|
||||
def _get_xctest_framework_search_paths_flags(ctx: "context") -> [["cmd_args", str.type]]:
|
||||
xctest_swiftmodule_search_path, xctest_framework_search_path = _get_xctest_framework_search_paths(ctx)
|
||||
return [
|
||||
"-I",
|
||||
xctest_swiftmodule_search_path,
|
||||
"-F",
|
||||
xctest_framework_search_path,
|
||||
]
|
||||
|
||||
def _get_xctest_framework_linker_flags(ctx: "context") -> [["cmd_args", str.type]]:
|
||||
xctest_swiftmodule_search_path, xctest_framework_search_path = _get_xctest_framework_search_paths(ctx)
|
||||
return [
|
||||
"-L",
|
||||
xctest_swiftmodule_search_path,
|
||||
"-F",
|
||||
xctest_framework_search_path,
|
||||
]
|
||||
24
vendor/cxx/tools/buck/prelude/apple/apple_test_macro_layer.bzl
vendored
Normal file
24
vendor/cxx/tools/buck/prelude/apple/apple_test_macro_layer.bzl
vendored
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load(":apple_bundle_config.bzl", "apple_bundle_config")
|
||||
load(":apple_macro_layer.bzl", "apple_macro_layer_set_bool_override_attrs_from_config")
|
||||
load(
|
||||
":apple_rules_impl_utility.bzl",
|
||||
"APPLE_LINK_LIBRARIES_LOCALLY_OVERRIDE_ATTR_NAME",
|
||||
)
|
||||
|
||||
_APPLE_TEST_LOCAL_EXECUTION_OVERRIDES = {
|
||||
APPLE_LINK_LIBRARIES_LOCALLY_OVERRIDE_ATTR_NAME: ("apple", "link_libraries_locally_override"),
|
||||
}
|
||||
|
||||
def apple_test_macro_impl(apple_test_rule = None, **kwargs):
|
||||
kwargs.update(apple_bundle_config())
|
||||
kwargs.update(apple_macro_layer_set_bool_override_attrs_from_config(_APPLE_TEST_LOCAL_EXECUTION_OVERRIDES))
|
||||
apple_test_rule(
|
||||
**kwargs
|
||||
)
|
||||
43
vendor/cxx/tools/buck/prelude/apple/apple_toolchain.bzl
vendored
Normal file
43
vendor/cxx/tools/buck/prelude/apple/apple_toolchain.bzl
vendored
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load("@prelude//apple:apple_toolchain_types.bzl", "AppleToolchainInfo")
|
||||
load("@prelude//apple:swift_toolchain_types.bzl", "SwiftToolchainInfo")
|
||||
load("@prelude//cxx:cxx_toolchain_types.bzl", "CxxPlatformInfo", "CxxToolchainInfo")
|
||||
|
||||
def apple_toolchain_impl(ctx: "context") -> ["provider"]:
|
||||
sdk_path = ctx.attrs._internal_sdk_path or ctx.attrs.sdk_path
|
||||
platform_path = ctx.attrs._internal_platform_path or ctx.attrs.platform_path
|
||||
return [
|
||||
DefaultInfo(),
|
||||
AppleToolchainInfo(
|
||||
actool = ctx.attrs.actool[RunInfo],
|
||||
ibtool = ctx.attrs.ibtool[RunInfo],
|
||||
dsymutil = ctx.attrs.dsymutil[RunInfo],
|
||||
dwarfdump = ctx.attrs.dwarfdump[RunInfo] if ctx.attrs.dwarfdump else None,
|
||||
lipo = ctx.attrs.lipo[RunInfo],
|
||||
cxx_platform_info = ctx.attrs.cxx_toolchain[CxxPlatformInfo],
|
||||
cxx_toolchain_info = ctx.attrs.cxx_toolchain[CxxToolchainInfo],
|
||||
codesign = ctx.attrs.codesign[RunInfo],
|
||||
codesign_allocate = ctx.attrs.codesign_allocate[RunInfo],
|
||||
codesign_identities_command = ctx.attrs.codesign_identities_command[RunInfo] if ctx.attrs.codesign_identities_command else None,
|
||||
compile_resources_locally = ctx.attrs.compile_resources_locally,
|
||||
libtool = ctx.attrs.libtool[RunInfo],
|
||||
momc = ctx.attrs.momc[RunInfo],
|
||||
min_version = ctx.attrs.min_version,
|
||||
xctest = ctx.attrs.xctest[RunInfo],
|
||||
platform_path = platform_path,
|
||||
sdk_name = ctx.attrs.sdk_name,
|
||||
sdk_path = sdk_path,
|
||||
sdk_version = ctx.attrs.version,
|
||||
sdk_build_version = ctx.attrs.build_version,
|
||||
swift_toolchain_info = ctx.attrs.swift_toolchain[SwiftToolchainInfo] if ctx.attrs.swift_toolchain else None,
|
||||
watch_kit_stub_binary = ctx.attrs.watch_kit_stub_binary,
|
||||
xcode_version = ctx.attrs.xcode_version,
|
||||
xcode_build_version = ctx.attrs.xcode_build_version,
|
||||
),
|
||||
]
|
||||
43
vendor/cxx/tools/buck/prelude/apple/apple_toolchain_types.bzl
vendored
Normal file
43
vendor/cxx/tools/buck/prelude/apple/apple_toolchain_types.bzl
vendored
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
AppleToolchainInfo = provider(fields = [
|
||||
"actool", # "RunInfo"
|
||||
"ibtool", # "RunInfo"
|
||||
"dsymutil", # "RunInfo"
|
||||
"dwarfdump", # ["RunInfo", None]
|
||||
"lipo", # "RunInfo"
|
||||
"cxx_platform_info", # "CxxPlatformInfo"
|
||||
"cxx_toolchain_info", # "CxxToolchainInfo"
|
||||
"codesign", # "RunInfo"
|
||||
"codesign_allocate", # "RunInfo"
|
||||
"codesign_identities_command", # ["RunInfo", None]
|
||||
"compile_resources_locally", # bool.type
|
||||
"libtool", # "RunInfo"
|
||||
"momc", # "RunInfo"
|
||||
"min_version", # [None, str.type]
|
||||
"xctest", # "RunInfo"
|
||||
"platform_path", # [str.type, artifact]
|
||||
# SDK name to be passed to tools (e.g. actool), equivalent to ApplePlatform::getExternalName() in v1.
|
||||
"sdk_name", # str.type
|
||||
"sdk_path", # [str.type, artifact]
|
||||
# TODO(T124581557) Make it non-optional once there is no "selected xcode" toolchain
|
||||
"sdk_version", # [None, str.type]
|
||||
"sdk_build_version", # "[None, str.type]"
|
||||
"swift_toolchain_info", # "SwiftToolchainInfo"
|
||||
"watch_kit_stub_binary", # "artifact"
|
||||
"xcode_version", # "[None, str.type]"
|
||||
"xcode_build_version", # "[None, str.type]"
|
||||
])
|
||||
|
||||
AppleToolsInfo = provider(fields = [
|
||||
"assemble_bundle", # RunInfo
|
||||
"info_plist_processor", # RunInfo
|
||||
"make_modulemap", # "RunInfo"
|
||||
"make_vfsoverlay", # "RunInfo"
|
||||
"swift_objc_header_postprocess", # "RunInfo"
|
||||
])
|
||||
82
vendor/cxx/tools/buck/prelude/apple/apple_utility.bzl
vendored
Normal file
82
vendor/cxx/tools/buck/prelude/apple/apple_utility.bzl
vendored
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load("@prelude//apple:apple_toolchain_types.bzl", "AppleToolchainInfo")
|
||||
load("@prelude//cxx:headers.bzl", "CxxHeadersLayout", "CxxHeadersNaming")
|
||||
load("@prelude//utils:utils.bzl", "value_or")
|
||||
load(":apple_target_sdk_version.bzl", "get_min_deployment_version_for_node")
|
||||
|
||||
_VERSION_PLACEHOLDER = "(VERSION)"
|
||||
|
||||
# TODO(T115177501): Make target triples part of the toolchains
|
||||
# Map from SDK name -> target triple _without_ leading architecture
|
||||
_TARGET_TRIPLE_MAP = {
|
||||
"iphoneos": "apple-ios{}".format(_VERSION_PLACEHOLDER),
|
||||
"iphonesimulator": "apple-ios{}-simulator".format(_VERSION_PLACEHOLDER),
|
||||
"macosx": "apple-macosx{}".format(_VERSION_PLACEHOLDER),
|
||||
"watchos": "apple-watchos{}".format(_VERSION_PLACEHOLDER),
|
||||
"watchsimulator": "apple-watchos{}-simulator".format(_VERSION_PLACEHOLDER),
|
||||
}
|
||||
|
||||
def get_apple_cxx_headers_layout(ctx: "context") -> CxxHeadersLayout.type:
|
||||
namespace = value_or(ctx.attrs.header_path_prefix, ctx.attrs.name)
|
||||
return CxxHeadersLayout(namespace = namespace, naming = CxxHeadersNaming("apple"))
|
||||
|
||||
def get_module_name(ctx: "context") -> str.type:
|
||||
return ctx.attrs.module_name or ctx.attrs.header_path_prefix or ctx.attrs.name
|
||||
|
||||
def has_apple_toolchain(ctx: "context") -> bool.type:
|
||||
return hasattr(ctx.attrs, "_apple_toolchain")
|
||||
|
||||
def get_versioned_target_triple(ctx: "context") -> str.type:
|
||||
apple_toolchain_info = ctx.attrs._apple_toolchain[AppleToolchainInfo]
|
||||
swift_toolchain_info = apple_toolchain_info.swift_toolchain_info
|
||||
|
||||
architecture = swift_toolchain_info.architecture
|
||||
if architecture == None:
|
||||
fail("Need to set `architecture` field of swift_toolchain(), target: {}".format(ctx.label))
|
||||
|
||||
target_sdk_version = get_min_deployment_version_for_node(ctx) or ""
|
||||
|
||||
sdk_name = apple_toolchain_info.sdk_name
|
||||
target_triple_with_version_placeholder = _TARGET_TRIPLE_MAP.get(sdk_name)
|
||||
if target_triple_with_version_placeholder == None:
|
||||
fail("Could not find target triple for sdk = {}".format(sdk_name))
|
||||
|
||||
versioned_target_triple = target_triple_with_version_placeholder.replace(_VERSION_PLACEHOLDER, target_sdk_version)
|
||||
return "{}-{}".format(architecture, versioned_target_triple)
|
||||
|
||||
def expand_relative_prefixed_sdk_path(
|
||||
sdk_path: "cmd_args",
|
||||
swift_resource_dir: "cmd_args",
|
||||
path_to_expand: str.type) -> "cmd_args":
|
||||
path_expansion_map = {
|
||||
"$RESOURCEDIR": swift_resource_dir,
|
||||
"$SDKROOT": sdk_path,
|
||||
}
|
||||
expanded_cmd = cmd_args()
|
||||
for (path_variable, path_value) in path_expansion_map.items():
|
||||
if path_to_expand.startswith(path_variable):
|
||||
path = path_to_expand[len(path_variable):]
|
||||
if path.find("$") == 0:
|
||||
fail("Failed to expand framework path: {}".format(path))
|
||||
expanded_cmd.add(cmd_args([path_value, path], delimiter = ""))
|
||||
|
||||
return expanded_cmd
|
||||
|
||||
def get_disable_pch_validation_flags() -> [str.type]:
|
||||
"""
|
||||
We need to disable PCH validation for some actions like Swift compilation and Swift PCM generation.
|
||||
Currently, we don't have a mechanism to compile with enabled pch validation and Swift explicit modules,
|
||||
which we need to be able to do while we are waiting for Anonymous targets which will allow us to solve this problem properly.
|
||||
"""
|
||||
return [
|
||||
"-Xcc",
|
||||
"-Xclang",
|
||||
"-Xcc",
|
||||
"-fno-validate-pch",
|
||||
]
|
||||
88
vendor/cxx/tools/buck/prelude/apple/modulemap.bzl
vendored
Normal file
88
vendor/cxx/tools/buck/prelude/apple/modulemap.bzl
vendored
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load("@prelude//apple:apple_toolchain_types.bzl", "AppleToolsInfo")
|
||||
load(
|
||||
"@prelude//cxx:headers.bzl",
|
||||
"CHeader", # @unused Used as a type
|
||||
)
|
||||
load(
|
||||
"@prelude//cxx:preprocessor.bzl",
|
||||
"CPreprocessor",
|
||||
)
|
||||
load(":apple_utility.bzl", "get_module_name")
|
||||
|
||||
def preprocessor_info_for_modulemap(ctx: "context", name: str.type, headers: [CHeader.type], swift_header: ["artifact", None]) -> "CPreprocessor":
|
||||
# We don't want to name this module.modulemap to avoid implicit importing
|
||||
if name == "module":
|
||||
fail("Don't use the name `module` for modulemaps, this will allow for implicit importing.")
|
||||
|
||||
module_name = get_module_name(ctx)
|
||||
|
||||
# Create a map of header import path to artifact location
|
||||
header_map = {}
|
||||
for h in headers:
|
||||
if h.namespace:
|
||||
header_map["{}/{}".format(h.namespace, h.name)] = h.artifact
|
||||
else:
|
||||
header_map[h.name] = h.artifact
|
||||
|
||||
# We need to include the Swift header in the symlink tree too
|
||||
swift_header_name = "{}/{}-Swift.h".format(module_name, module_name)
|
||||
if swift_header:
|
||||
header_map[swift_header_name] = swift_header
|
||||
|
||||
# Create a symlink dir for the headers to import
|
||||
symlink_tree = ctx.actions.symlinked_dir(name + "_symlink_tree", header_map)
|
||||
|
||||
# Create a modulemap at the root of that tree
|
||||
output = ctx.actions.declare_output(name + ".modulemap")
|
||||
cmd = cmd_args(ctx.attrs._apple_tools[AppleToolsInfo].make_modulemap)
|
||||
cmd.add([
|
||||
"--output",
|
||||
output.as_output(),
|
||||
"--name",
|
||||
get_module_name(ctx),
|
||||
"--symlink-tree",
|
||||
symlink_tree,
|
||||
])
|
||||
|
||||
if swift_header:
|
||||
cmd.add([
|
||||
"--swift-header",
|
||||
swift_header,
|
||||
])
|
||||
|
||||
if ctx.attrs.use_submodules:
|
||||
cmd.add("--use-submodules")
|
||||
|
||||
for hdr in sorted(header_map.keys()):
|
||||
# Don't include the Swift header in the mappings, this is handled separately.
|
||||
if hdr != swift_header_name:
|
||||
cmd.add(hdr)
|
||||
|
||||
ctx.actions.run(cmd, category = "modulemap", identifier = name)
|
||||
|
||||
return CPreprocessor(
|
||||
modular_args = _args_for_modulemap(output, symlink_tree, swift_header),
|
||||
modulemap_path = cmd_args(output).hidden(cmd_args(symlink_tree)),
|
||||
args = _exported_preprocessor_args(symlink_tree),
|
||||
)
|
||||
|
||||
def _args_for_modulemap(
|
||||
modulemap: "artifact",
|
||||
symlink_tree: "artifact",
|
||||
swift_header: ["artifact", None]) -> ["cmd_args"]:
|
||||
cmd = cmd_args(modulemap, format = "-fmodule-map-file={}")
|
||||
cmd.hidden(symlink_tree)
|
||||
if swift_header:
|
||||
cmd.hidden(swift_header)
|
||||
|
||||
return [cmd]
|
||||
|
||||
def _exported_preprocessor_args(symlink_tree: "artifact") -> ["cmd_args"]:
|
||||
return [cmd_args(symlink_tree, format = "-I{}")]
|
||||
105
vendor/cxx/tools/buck/prelude/apple/prebuilt_apple_framework.bzl
vendored
Normal file
105
vendor/cxx/tools/buck/prelude/apple/prebuilt_apple_framework.bzl
vendored
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load(
|
||||
"@prelude//cxx:cxx_library_utility.bzl",
|
||||
"cxx_attr_exported_linker_flags",
|
||||
"cxx_platform_supported",
|
||||
)
|
||||
load(
|
||||
"@prelude//cxx:preprocessor.bzl",
|
||||
"CPreprocessor",
|
||||
"cxx_inherited_preprocessor_infos",
|
||||
"cxx_merge_cpreprocessors",
|
||||
)
|
||||
load(
|
||||
"@prelude//linking:link_groups.bzl",
|
||||
"merge_link_group_lib_info",
|
||||
)
|
||||
load(
|
||||
"@prelude//linking:link_info.bzl",
|
||||
"LinkInfo",
|
||||
"LinkInfos",
|
||||
"LinkStyle",
|
||||
"Linkage",
|
||||
"create_merged_link_info",
|
||||
)
|
||||
load(
|
||||
"@prelude//linking:linkable_graph.bzl",
|
||||
"create_linkable_graph",
|
||||
"create_linkable_graph_node",
|
||||
"create_linkable_node",
|
||||
)
|
||||
load(
|
||||
"@prelude//linking:shared_libraries.bzl",
|
||||
"SharedLibraryInfo",
|
||||
"merge_shared_libraries",
|
||||
)
|
||||
load("@prelude//utils:utils.bzl", "filter_and_map_idx")
|
||||
load(":apple_bundle_types.bzl", "AppleBundleInfo")
|
||||
load(":apple_frameworks.bzl", "to_framework_name")
|
||||
|
||||
def prebuilt_apple_framework_impl(ctx: "context") -> ["provider"]:
|
||||
providers = []
|
||||
|
||||
framework_directory_artifact = ctx.attrs.framework
|
||||
|
||||
# Check this rule's `supported_platforms_regex` with the current platform.
|
||||
if cxx_platform_supported(ctx):
|
||||
# Sandbox the framework, to avoid leaking other frameworks via search paths.
|
||||
framework_name = to_framework_name(framework_directory_artifact.basename)
|
||||
framework_dir = ctx.actions.symlinked_dir(
|
||||
"Frameworks",
|
||||
{framework_name + ".framework": framework_directory_artifact},
|
||||
)
|
||||
|
||||
# Add framework & pp info from deps.
|
||||
inherited_pp_info = cxx_inherited_preprocessor_infos(ctx.attrs.deps)
|
||||
providers.append(cxx_merge_cpreprocessors(
|
||||
ctx,
|
||||
[CPreprocessor(args = ["-F", framework_dir])],
|
||||
inherited_pp_info,
|
||||
))
|
||||
|
||||
# Add framework to link args.
|
||||
# TODO(T110378120): Support shared linking for mac targets:
|
||||
# https://fburl.com/code/pqrtt1qr.
|
||||
args = []
|
||||
args.extend(cxx_attr_exported_linker_flags(ctx))
|
||||
args.extend(["-F", framework_dir])
|
||||
args.extend(["-framework", framework_name])
|
||||
link = LinkInfo(
|
||||
name = framework_name,
|
||||
pre_flags = args,
|
||||
)
|
||||
providers.append(create_merged_link_info(
|
||||
ctx,
|
||||
{link_style: LinkInfos(default = link) for link_style in LinkStyle},
|
||||
))
|
||||
|
||||
# Create, augment and provide the linkable graph.
|
||||
linkable_graph = create_linkable_graph(
|
||||
ctx,
|
||||
node = create_linkable_graph_node(
|
||||
ctx,
|
||||
linkable_node = create_linkable_node(
|
||||
ctx,
|
||||
preferred_linkage = Linkage("shared"),
|
||||
link_infos = {LinkStyle("shared"): LinkInfos(default = link)},
|
||||
),
|
||||
excluded = {ctx.label: None},
|
||||
),
|
||||
)
|
||||
providers.append(linkable_graph)
|
||||
|
||||
# The default output is the provided framework.
|
||||
providers.append(DefaultInfo(default_outputs = [framework_directory_artifact]))
|
||||
providers.append(AppleBundleInfo(bundle = framework_directory_artifact, is_watchos = None))
|
||||
providers.append(merge_link_group_lib_info(deps = ctx.attrs.deps))
|
||||
providers.append(merge_shared_libraries(ctx.actions, deps = filter_and_map_idx(SharedLibraryInfo, ctx.attrs.deps)))
|
||||
|
||||
return providers
|
||||
148
vendor/cxx/tools/buck/prelude/apple/resource_groups.bzl
vendored
Normal file
148
vendor/cxx/tools/buck/prelude/apple/resource_groups.bzl
vendored
Normal file
|
|
@ -0,0 +1,148 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load(
|
||||
"@prelude//cxx:groups.bzl",
|
||||
"MATCH_ALL_LABEL",
|
||||
)
|
||||
load(
|
||||
"@prelude//utils:graph_utils.bzl",
|
||||
"breadth_first_traversal_by",
|
||||
)
|
||||
load(":apple_asset_catalog_types.bzl", "AppleAssetCatalogSpec")
|
||||
load(":apple_core_data_types.bzl", "AppleCoreDataSpec")
|
||||
load(":apple_resource_types.bzl", "AppleResourceSpec")
|
||||
|
||||
ResourceGroupInfo = provider(fields = [
|
||||
"groups", # [Group.type]
|
||||
"groups_hash", # str.type
|
||||
"mappings", # {"label": str.type}
|
||||
])
|
||||
|
||||
ResourceGraphNode = record(
|
||||
label = field("label"),
|
||||
# Attribute labels on the target.
|
||||
labels = field([str.type], []),
|
||||
# Deps of this target which might have resources transitively.
|
||||
deps = field(["label"], []),
|
||||
# Exported deps of this target which might have resources transitively.
|
||||
exported_deps = field(["label"], []),
|
||||
# Actual resource data, present when node corresponds to `apple_resource` target.
|
||||
resource_spec = field([AppleResourceSpec.type, None], None),
|
||||
# Actual asset catalog data, present when node corresponds to `apple_asset_catalog` target.
|
||||
asset_catalog_spec = field([AppleAssetCatalogSpec.type, None], None),
|
||||
# Actual core data, present when node corresponds to `core_data_model` target
|
||||
core_data_spec = field([AppleCoreDataSpec.type, None], None),
|
||||
)
|
||||
|
||||
ResourceGraphTSet = transitive_set()
|
||||
|
||||
ResourceGraph = provider(fields = [
|
||||
"label", # "label"
|
||||
"nodes", # "ResourceGraphTSet"
|
||||
])
|
||||
|
||||
def create_resource_graph(
|
||||
ctx: "context",
|
||||
labels: [str.type],
|
||||
deps: ["dependency"],
|
||||
exported_deps: ["dependency"],
|
||||
resource_spec: [AppleResourceSpec.type, None] = None,
|
||||
asset_catalog_spec: [AppleAssetCatalogSpec.type, None] = None,
|
||||
core_data_spec: [AppleCoreDataSpec.type, None] = None) -> ResourceGraph.type:
|
||||
node = ResourceGraphNode(
|
||||
label = ctx.label,
|
||||
labels = labels,
|
||||
deps = _with_resources_deps(deps),
|
||||
exported_deps = _with_resources_deps(exported_deps),
|
||||
resource_spec = resource_spec,
|
||||
asset_catalog_spec = asset_catalog_spec,
|
||||
core_data_spec = core_data_spec,
|
||||
)
|
||||
all_deps = deps + exported_deps
|
||||
child_nodes = filter(None, [d.get(ResourceGraph) for d in all_deps])
|
||||
return ResourceGraph(
|
||||
label = ctx.label,
|
||||
nodes = ctx.actions.tset(ResourceGraphTSet, value = node, children = [child_node.nodes for child_node in child_nodes]),
|
||||
)
|
||||
|
||||
def get_resource_graph_node_map_func(graph: ResourceGraph.type):
|
||||
def get_resource_graph_node_map() -> {"label": ResourceGraphNode.type}:
|
||||
nodes = graph.nodes.traverse()
|
||||
return {node.label: node for node in filter(None, nodes)}
|
||||
|
||||
return get_resource_graph_node_map
|
||||
|
||||
def _with_resources_deps(deps: ["dependency"]) -> ["label"]:
|
||||
"""
|
||||
Filters dependencies and returns only those which are relevant
|
||||
to working with resources i.e. those which contains resource graph provider.
|
||||
"""
|
||||
graphs = filter(None, [d.get(ResourceGraph) for d in deps])
|
||||
return [g.label for g in graphs]
|
||||
|
||||
def get_resource_group_info(ctx: "context") -> [ResourceGroupInfo.type, None]:
|
||||
"""
|
||||
Parses the currently analyzed context for any resource group definitions
|
||||
and returns a list of all resource groups with their mappings.
|
||||
"""
|
||||
resource_group_map = ctx.attrs.resource_group_map
|
||||
|
||||
if not resource_group_map:
|
||||
return None
|
||||
|
||||
if type(resource_group_map) == "dependency":
|
||||
return resource_group_map[ResourceGroupInfo]
|
||||
|
||||
fail("Resource group maps must be provided as a resource_group_map rule dependency.")
|
||||
|
||||
def get_filtered_resources(
|
||||
root: "label",
|
||||
resource_graph_node_map_func,
|
||||
resource_group: [str.type, None],
|
||||
resource_group_mappings: [{"label": str.type}, None]) -> ([AppleResourceSpec.type], [AppleAssetCatalogSpec.type], [AppleCoreDataSpec.type]):
|
||||
"""
|
||||
Walks the provided DAG and collects resources matching resource groups definition.
|
||||
"""
|
||||
|
||||
resource_graph_node_map = resource_graph_node_map_func()
|
||||
|
||||
def get_traversed_deps(target: "label") -> ["label"]:
|
||||
node = resource_graph_node_map[target] # buildifier: disable=uninitialized
|
||||
return node.exported_deps + node.deps
|
||||
|
||||
targets = breadth_first_traversal_by(
|
||||
resource_graph_node_map,
|
||||
get_traversed_deps(root),
|
||||
get_traversed_deps,
|
||||
)
|
||||
|
||||
resource_specs = []
|
||||
asset_catalog_specs = []
|
||||
core_data_specs = []
|
||||
|
||||
for target in targets:
|
||||
target_resource_group = resource_group_mappings.get(target)
|
||||
|
||||
# Ungrouped targets belong to the unlabeled bundle
|
||||
if ((not target_resource_group and not resource_group) or
|
||||
# Does it match special "MATCH_ALL" mapping?
|
||||
target_resource_group == MATCH_ALL_LABEL or
|
||||
# Does it match currently evaluated group?
|
||||
target_resource_group == resource_group):
|
||||
node = resource_graph_node_map[target]
|
||||
resource_spec = node.resource_spec
|
||||
if resource_spec:
|
||||
resource_specs.append(resource_spec)
|
||||
asset_catalog_spec = node.asset_catalog_spec
|
||||
if asset_catalog_spec:
|
||||
asset_catalog_specs.append(asset_catalog_spec)
|
||||
core_data_spec = node.core_data_spec
|
||||
if core_data_spec:
|
||||
core_data_specs.append(core_data_spec)
|
||||
|
||||
return resource_specs, asset_catalog_specs, core_data_specs
|
||||
474
vendor/cxx/tools/buck/prelude/apple/swift_compilation.bzl
vendored
Normal file
474
vendor/cxx/tools/buck/prelude/apple/swift_compilation.bzl
vendored
Normal file
|
|
@ -0,0 +1,474 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load("@prelude//:paths.bzl", "paths")
|
||||
load("@prelude//apple:apple_toolchain_types.bzl", "AppleToolsInfo")
|
||||
load(
|
||||
"@prelude//cxx:compile.bzl",
|
||||
"CxxSrcWithFlags", # @unused Used as a type
|
||||
)
|
||||
load("@prelude//cxx:cxx_types.bzl", "CxxAdditionalArgsfileParams")
|
||||
load("@prelude//cxx:headers.bzl", "CHeader")
|
||||
load(
|
||||
"@prelude//cxx:preprocessor.bzl",
|
||||
"CPreprocessor",
|
||||
"cxx_inherited_preprocessor_infos",
|
||||
"cxx_merge_cpreprocessors",
|
||||
)
|
||||
load(":apple_sdk_modules_utility.bzl", "get_sdk_deps_tset", "is_sdk_modules_provided")
|
||||
load(":apple_toolchain_types.bzl", "AppleToolchainInfo")
|
||||
load(":apple_utility.bzl", "get_disable_pch_validation_flags", "get_module_name", "get_versioned_target_triple")
|
||||
load(":modulemap.bzl", "preprocessor_info_for_modulemap")
|
||||
load(":swift_module_map.bzl", "write_swift_module_map_with_swift_deps")
|
||||
load(":swift_pcm_compilation.bzl", "compile_swift_pcm", "get_pcm_deps_tset")
|
||||
|
||||
def _add_swiftmodule_search_path(swiftmodule_path: "artifact"):
|
||||
# Value will contain a path to the artifact,
|
||||
# while we need only the folder which contains the artifact.
|
||||
return ["-I", cmd_args(swiftmodule_path).parent()]
|
||||
|
||||
def _hidden_projection(swiftmodule_path: "artifact"):
|
||||
return swiftmodule_path
|
||||
|
||||
def _linker_args_projection(swiftmodule_path: "artifact"):
|
||||
return cmd_args(swiftmodule_path, format = "-Wl,-add_ast_path,{}")
|
||||
|
||||
SwiftmodulePathsTSet = transitive_set(args_projections = {
|
||||
"hidden": _hidden_projection,
|
||||
"linker_args": _linker_args_projection,
|
||||
"module_search_path": _add_swiftmodule_search_path,
|
||||
})
|
||||
|
||||
ExportedHeadersTSet = transitive_set()
|
||||
|
||||
SwiftDependencyInfo = provider(fields = [
|
||||
"exported_headers", # ExportedHeadersTSet of {"module_name": [exported_headers]}
|
||||
"exported_swiftmodule_paths", # SwiftmodulePathsTSet of artifact that includes only paths through exported_deps, used for compilation
|
||||
"transitive_swiftmodule_paths", # SwiftmodulePathsTSet of artifact that includes all transitive paths, used for linking
|
||||
])
|
||||
|
||||
SwiftCompilationOutput = record(
|
||||
# The object files output from compilation.
|
||||
object_files = field(["artifact"]),
|
||||
# The swiftmodule file output from compilation.
|
||||
swiftmodule = field("artifact"),
|
||||
# The dependency info provider that provides the swiftmodule
|
||||
# search paths required for compilation.
|
||||
providers = field([["SwiftPCMCompilationInfo", "SwiftDependencyInfo"]]),
|
||||
# Preprocessor info required for ObjC compilation of this library.
|
||||
pre = field(CPreprocessor.type),
|
||||
# Exported preprocessor info required for ObjC compilation of rdeps.
|
||||
exported_pre = field(CPreprocessor.type),
|
||||
# Argsfile to compile an object file which is used by some subtargets.
|
||||
swift_argsfile = field("CxxAdditionalArgsfileParams"),
|
||||
)
|
||||
|
||||
_REQUIRED_SDK_MODULES = ["Swift", "SwiftOnoneSupport", "Darwin", "_Concurrency"]
|
||||
|
||||
def compile_swift(
|
||||
ctx: "context",
|
||||
srcs: [CxxSrcWithFlags.type],
|
||||
exported_headers: [CHeader.type],
|
||||
objc_modulemap_pp_info: ["CPreprocessor", None],
|
||||
extra_search_paths_flags: ["_arglike"] = []) -> ["SwiftCompilationOutput", None]:
|
||||
if not srcs:
|
||||
return None
|
||||
|
||||
toolchain = ctx.attrs._apple_toolchain[AppleToolchainInfo].swift_toolchain_info
|
||||
|
||||
module_name = get_module_name(ctx)
|
||||
output_header = ctx.actions.declare_output(module_name + "-Swift.h")
|
||||
output_object = ctx.actions.declare_output(module_name + ".o")
|
||||
output_swiftmodule = ctx.actions.declare_output(module_name + ".swiftmodule")
|
||||
|
||||
shared_flags = _get_shared_flags(
|
||||
ctx,
|
||||
module_name,
|
||||
exported_headers,
|
||||
objc_modulemap_pp_info,
|
||||
extra_search_paths_flags,
|
||||
)
|
||||
|
||||
if toolchain.can_toolchain_emit_obj_c_header_textually:
|
||||
_compile_swiftmodule(ctx, toolchain, shared_flags, srcs, output_swiftmodule, output_header)
|
||||
else:
|
||||
unprocessed_header = ctx.actions.declare_output(module_name + "-SwiftUnprocessed.h")
|
||||
_compile_swiftmodule(ctx, toolchain, shared_flags, srcs, output_swiftmodule, unprocessed_header)
|
||||
_perform_swift_postprocessing(ctx, module_name, unprocessed_header, output_header)
|
||||
|
||||
swift_argsfile = _compile_object(ctx, toolchain, shared_flags, srcs, output_object)
|
||||
|
||||
# Swift libraries extend the ObjC modulemaps to include the -Swift.h header
|
||||
modulemap_pp_info = preprocessor_info_for_modulemap(ctx, "swift-extended", exported_headers, output_header)
|
||||
exported_swift_header = CHeader(
|
||||
artifact = output_header,
|
||||
name = output_header.basename,
|
||||
namespace = module_name,
|
||||
named = False,
|
||||
)
|
||||
exported_pp_info = CPreprocessor(
|
||||
headers = [exported_swift_header],
|
||||
modular_args = modulemap_pp_info.modular_args,
|
||||
args = modulemap_pp_info.args,
|
||||
modulemap_path = modulemap_pp_info.modulemap_path,
|
||||
)
|
||||
|
||||
# We also need to include the unprefixed -Swift.h header in this libraries preprocessor info
|
||||
swift_header = CHeader(
|
||||
artifact = output_header,
|
||||
name = output_header.basename,
|
||||
namespace = "",
|
||||
named = False,
|
||||
)
|
||||
pre = CPreprocessor(headers = [swift_header])
|
||||
|
||||
# Pass up the swiftmodule paths for this module and its exported_deps
|
||||
return SwiftCompilationOutput(
|
||||
object_files = [output_object],
|
||||
swiftmodule = output_swiftmodule,
|
||||
providers = [get_swift_dependency_info(ctx, exported_pp_info, output_swiftmodule)],
|
||||
pre = pre,
|
||||
exported_pre = exported_pp_info,
|
||||
swift_argsfile = swift_argsfile,
|
||||
)
|
||||
|
||||
# Swift headers are postprocessed to make them compatible with Objective-C
|
||||
# compilation that does not use -fmodules. This is a workaround for the bad
|
||||
# performance of -fmodules without Explicit Modules, once Explicit Modules is
|
||||
# supported, this postprocessing should be removed.
|
||||
def _perform_swift_postprocessing(
|
||||
ctx: "context",
|
||||
module_name: "string",
|
||||
unprocessed_header: "artifact",
|
||||
output_header: "artifact"):
|
||||
transitive_exported_headers = {
|
||||
module: module_exported_headers
|
||||
for exported_headers_map in _get_exported_headers_tset(ctx).traverse()
|
||||
if exported_headers_map
|
||||
for module, module_exported_headers in exported_headers_map.items()
|
||||
}
|
||||
deps_json = ctx.actions.write_json(module_name + "-Deps.json", transitive_exported_headers)
|
||||
postprocess_cmd = cmd_args(ctx.attrs._apple_tools[AppleToolsInfo].swift_objc_header_postprocess)
|
||||
postprocess_cmd.add([
|
||||
unprocessed_header,
|
||||
deps_json,
|
||||
output_header.as_output(),
|
||||
])
|
||||
ctx.actions.run(postprocess_cmd, category = "swift_objc_header_postprocess")
|
||||
|
||||
# We use separate actions for swiftmodule and object file output. This
|
||||
# improves build parallelism at the cost of duplicated work, but by disabling
|
||||
# type checking in function bodies the swiftmodule compilation can be done much
|
||||
# faster than object file output.
|
||||
def _compile_swiftmodule(
|
||||
ctx: "context",
|
||||
toolchain: "SwiftToolchainInfo",
|
||||
shared_flags: "cmd_args",
|
||||
srcs: [CxxSrcWithFlags.type],
|
||||
output_swiftmodule: "artifact",
|
||||
output_header: "artifact") -> "CxxAdditionalArgsfileParams":
|
||||
argfile_cmd = cmd_args(shared_flags)
|
||||
argfile_cmd.add([
|
||||
"-Xfrontend",
|
||||
"-experimental-skip-non-inlinable-function-bodies-without-types",
|
||||
"-emit-module",
|
||||
"-emit-objc-header",
|
||||
])
|
||||
cmd = cmd_args([
|
||||
"-emit-module-path",
|
||||
output_swiftmodule.as_output(),
|
||||
"-emit-objc-header-path",
|
||||
output_header.as_output(),
|
||||
])
|
||||
return _compile_with_argsfile(ctx, "swiftmodule_compile", argfile_cmd, srcs, cmd, toolchain)
|
||||
|
||||
def _compile_object(
|
||||
ctx: "context",
|
||||
toolchain: "SwiftToolchainInfo",
|
||||
shared_flags: "cmd_args",
|
||||
srcs: [CxxSrcWithFlags.type],
|
||||
output_object: "artifact") -> "CxxAdditionalArgsfileParams":
|
||||
cmd = cmd_args([
|
||||
"-emit-object",
|
||||
"-o",
|
||||
output_object.as_output(),
|
||||
])
|
||||
return _compile_with_argsfile(ctx, "swift_compile", shared_flags, srcs, cmd, toolchain)
|
||||
|
||||
def _compile_with_argsfile(
|
||||
ctx: "context",
|
||||
name: str.type,
|
||||
shared_flags: "cmd_args",
|
||||
srcs: [CxxSrcWithFlags.type],
|
||||
additional_flags: "cmd_args",
|
||||
toolchain: "SwiftToolchainInfo") -> "CxxAdditionalArgsfileParams":
|
||||
shell_quoted_args = cmd_args(shared_flags, quote = "shell")
|
||||
argfile, _ = ctx.actions.write(name + ".argsfile", shell_quoted_args, allow_args = True)
|
||||
|
||||
cmd = cmd_args(toolchain.compiler)
|
||||
cmd.add(additional_flags)
|
||||
cmd.add(cmd_args(["@", argfile], delimiter = ""))
|
||||
|
||||
cmd.add([s.file for s in srcs])
|
||||
|
||||
# Swift compilation on RE without explicit modules is impractically expensive
|
||||
# because there's no shared module cache across different libraries.
|
||||
prefer_local = not _uses_explicit_modules(ctx)
|
||||
|
||||
# Argsfile should also depend on all artifacts in it, otherwise they won't be materialised.
|
||||
cmd.hidden([shell_quoted_args])
|
||||
|
||||
# If we prefer to execute locally (e.g., for perf reasons), ensure we upload to the cache,
|
||||
# so that CI builds populate caches used by developer machines.
|
||||
ctx.actions.run(cmd, category = name, prefer_local = prefer_local, allow_cache_upload = prefer_local)
|
||||
|
||||
hidden_args = [shared_flags]
|
||||
return CxxAdditionalArgsfileParams(file = argfile, hidden_args = hidden_args, extension = ".swift")
|
||||
|
||||
def _get_shared_flags(
|
||||
ctx: "context",
|
||||
module_name: str.type,
|
||||
objc_headers: [CHeader.type],
|
||||
objc_modulemap_pp_info: ["CPreprocessor", None],
|
||||
extra_search_paths_flags: ["_arglike"] = []) -> "cmd_args":
|
||||
toolchain = ctx.attrs._apple_toolchain[AppleToolchainInfo].swift_toolchain_info
|
||||
cmd = cmd_args()
|
||||
cmd.add([
|
||||
# This allows us to use a relative path for the compiler resource directory.
|
||||
"-working-directory",
|
||||
".",
|
||||
"-sdk",
|
||||
toolchain.sdk_path,
|
||||
"-target",
|
||||
get_versioned_target_triple(ctx),
|
||||
"-wmo",
|
||||
"-module-name",
|
||||
module_name,
|
||||
"-parse-as-library",
|
||||
# Disable Clang module breadcrumbs in the DWARF info. These will not be
|
||||
# debug prefix mapped and are not shareable across machines.
|
||||
"-Xfrontend",
|
||||
"-no-clang-module-breadcrumbs",
|
||||
])
|
||||
|
||||
if _uses_explicit_modules(ctx):
|
||||
cmd.add(get_disable_pch_validation_flags())
|
||||
|
||||
if toolchain.resource_dir:
|
||||
cmd.add([
|
||||
"-resource-dir",
|
||||
toolchain.resource_dir,
|
||||
])
|
||||
|
||||
if ctx.attrs.swift_version:
|
||||
cmd.add(["-swift-version", ctx.attrs.swift_version])
|
||||
|
||||
if ctx.attrs.enable_cxx_interop:
|
||||
cmd.add(["-enable-experimental-cxx-interop"])
|
||||
|
||||
serialize_debugging_options = False
|
||||
if ctx.attrs.serialize_debugging_options:
|
||||
if objc_headers:
|
||||
# TODO(T99100029): We cannot use VFS overlays with Buck2, so we have to disable
|
||||
# serializing debugging options for mixed libraries to debug successfully
|
||||
warning("Mixed libraries cannot serialize debugging options, disabling for module `{}` in rule `{}`".format(module_name, ctx.label))
|
||||
elif not toolchain.prefix_serialized_debugging_options:
|
||||
warning("The current toolchain does not support prefixing serialized debugging options, disabling for module `{}` in rule `{}`".format(module_name, ctx.label))
|
||||
else:
|
||||
# Apply the debug prefix map to Swift serialized debugging info.
|
||||
# This will allow for debugging remotely built swiftmodule files.
|
||||
serialize_debugging_options = True
|
||||
|
||||
if serialize_debugging_options:
|
||||
cmd.add([
|
||||
"-Xfrontend",
|
||||
"-serialize-debugging-options",
|
||||
"-Xfrontend",
|
||||
"-prefix-serialized-debugging-options",
|
||||
])
|
||||
else:
|
||||
cmd.add([
|
||||
"-Xfrontend",
|
||||
"-no-serialize-debugging-options",
|
||||
])
|
||||
|
||||
if toolchain.can_toolchain_emit_obj_c_header_textually:
|
||||
cmd.add([
|
||||
"-Xfrontend",
|
||||
"-emit-objc-header-textually",
|
||||
])
|
||||
|
||||
# Add flags required to import ObjC module dependencies
|
||||
_add_clang_deps_flags(ctx, cmd)
|
||||
_add_swift_deps_flags(ctx, cmd)
|
||||
|
||||
# Add flags for importing the ObjC part of this library
|
||||
_add_mixed_library_flags_to_cmd(cmd, objc_headers, objc_modulemap_pp_info)
|
||||
|
||||
# Add toolchain and target flags last to allow for overriding defaults
|
||||
cmd.add(toolchain.compiler_flags)
|
||||
cmd.add(ctx.attrs.swift_compiler_flags)
|
||||
cmd.add(extra_search_paths_flags)
|
||||
|
||||
return cmd
|
||||
|
||||
def _add_swift_deps_flags(ctx: "context", cmd: "cmd_args"):
|
||||
# If Explicit Modules are enabled, a few things must be provided to a compilation job:
|
||||
# 1. Direct and transitive SDK deps from `sdk_modules` attribute.
|
||||
# 2. Direct and transitive user-defined deps.
|
||||
# 3. Transitive SDK deps of user-defined deps.
|
||||
# (This is the case, when a user-defined dep exports a type from SDK module,
|
||||
# thus such SDK module should be implicitly visible to consumers of that custom dep)
|
||||
if _uses_explicit_modules(ctx):
|
||||
toolchain = ctx.attrs._apple_toolchain[AppleToolchainInfo].swift_toolchain_info
|
||||
module_name = get_module_name(ctx)
|
||||
sdk_deps_tset = get_sdk_deps_tset(
|
||||
ctx,
|
||||
module_name,
|
||||
ctx.attrs.deps + ctx.attrs.exported_deps,
|
||||
_REQUIRED_SDK_MODULES,
|
||||
toolchain,
|
||||
)
|
||||
swift_deps_tset = ctx.actions.tset(
|
||||
SwiftmodulePathsTSet,
|
||||
children = _get_swift_paths_tsets(ctx.attrs.deps + ctx.attrs.exported_deps),
|
||||
)
|
||||
swift_module_map_artifact = write_swift_module_map_with_swift_deps(
|
||||
ctx,
|
||||
module_name,
|
||||
list(sdk_deps_tset.traverse()),
|
||||
list(swift_deps_tset.traverse()),
|
||||
)
|
||||
cmd.add([
|
||||
"-Xfrontend",
|
||||
"-disable-implicit-swift-modules",
|
||||
"-Xfrontend",
|
||||
"-explicit-swift-module-map-file",
|
||||
"-Xfrontend",
|
||||
swift_module_map_artifact,
|
||||
])
|
||||
|
||||
# Add Clang sdk modules which do not go to swift modulemap
|
||||
cmd.add(sdk_deps_tset.project_as_args("clang_deps"))
|
||||
|
||||
# Swift compilation should depend on transitive Swift modules from swift-module-map.
|
||||
cmd.hidden(sdk_deps_tset.project_as_args("hidden"))
|
||||
cmd.hidden(swift_deps_tset.project_as_args("hidden"))
|
||||
else:
|
||||
depset = ctx.actions.tset(SwiftmodulePathsTSet, children = _get_swift_paths_tsets(ctx.attrs.deps + ctx.attrs.exported_deps))
|
||||
cmd.add(depset.project_as_args("module_search_path"))
|
||||
|
||||
def _add_clang_deps_flags(ctx: "context", cmd: "cmd_args") -> None:
|
||||
# If a module uses Explicit Modules, all direct and
|
||||
# transitive Clang deps have to be explicitly added.
|
||||
if _uses_explicit_modules(ctx):
|
||||
pcm_deps_tset = get_pcm_deps_tset(ctx, ctx.attrs.deps + ctx.attrs.exported_deps)
|
||||
cmd.add(pcm_deps_tset.project_as_args("clang_deps"))
|
||||
else:
|
||||
inherited_preprocessor_infos = cxx_inherited_preprocessor_infos(ctx.attrs.deps + ctx.attrs.exported_deps)
|
||||
preprocessors = cxx_merge_cpreprocessors(ctx, [], inherited_preprocessor_infos)
|
||||
cmd.add(cmd_args(preprocessors.set.project_as_args("args"), prepend = "-Xcc"))
|
||||
cmd.add(cmd_args(preprocessors.set.project_as_args("modular_args"), prepend = "-Xcc"))
|
||||
cmd.add(cmd_args(preprocessors.set.project_as_args("include_dirs"), prepend = "-Xcc"))
|
||||
|
||||
def _add_mixed_library_flags_to_cmd(
|
||||
cmd: "cmd_args",
|
||||
objc_headers: [CHeader.type],
|
||||
objc_modulemap_pp_info: ["CPreprocessor", None]) -> None:
|
||||
if not objc_headers:
|
||||
return
|
||||
|
||||
# TODO(T99100029): We cannot use VFS overlays to mask this import from
|
||||
# the debugger as they require absolute paths. Instead we will enforce
|
||||
# that mixed libraries do not have serialized debugging info and rely on
|
||||
# rdeps to serialize the correct paths.
|
||||
for arg in objc_modulemap_pp_info.args:
|
||||
cmd.add("-Xcc")
|
||||
cmd.add(arg)
|
||||
|
||||
for arg in objc_modulemap_pp_info.modular_args:
|
||||
cmd.add("-Xcc")
|
||||
cmd.add(arg)
|
||||
|
||||
cmd.add("-import-underlying-module")
|
||||
|
||||
def _get_swift_paths_tsets(deps: ["dependency"]) -> ["SwiftmodulePathsTSet"]:
|
||||
return [
|
||||
d[SwiftDependencyInfo].exported_swiftmodule_paths
|
||||
for d in deps
|
||||
if SwiftDependencyInfo in d
|
||||
]
|
||||
|
||||
def _get_transitive_swift_paths_tsets(deps: ["dependency"]) -> ["SwiftmodulePathsTSet"]:
|
||||
return [
|
||||
d[SwiftDependencyInfo].transitive_swiftmodule_paths
|
||||
for d in deps
|
||||
if SwiftDependencyInfo in d
|
||||
]
|
||||
|
||||
def _get_exported_headers_tset(ctx: "context", exported_headers: [["string"], None] = None) -> "ExportedHeadersTSet":
|
||||
return ctx.actions.tset(
|
||||
ExportedHeadersTSet,
|
||||
value = {get_module_name(ctx): exported_headers} if exported_headers else None,
|
||||
children = [
|
||||
dep.exported_headers
|
||||
for dep in [x.get(SwiftDependencyInfo) for x in ctx.attrs.exported_deps]
|
||||
if dep and dep.exported_headers
|
||||
],
|
||||
)
|
||||
|
||||
def get_swift_pcm_compile_info(
|
||||
ctx: "context",
|
||||
propagated_exported_preprocessor_info: ["CPreprocessorInfo", None],
|
||||
exported_pre: ["CPreprocessor", None]) -> ["SwiftPCMCompilationInfo", None]:
|
||||
swift_toolchain = ctx.attrs._apple_toolchain[AppleToolchainInfo].swift_toolchain_info
|
||||
|
||||
# If a toolchain supports explicit modules, exported PP exists and a target is modular,
|
||||
# let's precompile a modulemap in order to enable consumptions by Swift.
|
||||
if is_sdk_modules_provided(swift_toolchain) and exported_pre and exported_pre.modulemap_path and ctx.attrs.modular:
|
||||
return compile_swift_pcm(
|
||||
ctx,
|
||||
exported_pre,
|
||||
propagated_exported_preprocessor_info,
|
||||
)
|
||||
return None
|
||||
|
||||
def get_swift_dependency_info(
|
||||
ctx: "context",
|
||||
exported_pre: ["CPreprocessor", None],
|
||||
output_module: ["artifact", None]) -> "SwiftDependencyInfo":
|
||||
all_deps = ctx.attrs.exported_deps + ctx.attrs.deps
|
||||
if ctx.attrs.reexport_all_header_dependencies:
|
||||
exported_deps = all_deps
|
||||
else:
|
||||
exported_deps = ctx.attrs.exported_deps
|
||||
|
||||
exported_headers = [_header_basename(header) for header in ctx.attrs.exported_headers]
|
||||
exported_headers += [header.name for header in exported_pre.headers] if exported_pre else []
|
||||
|
||||
if output_module:
|
||||
exported_swiftmodules = ctx.actions.tset(SwiftmodulePathsTSet, value = output_module, children = _get_swift_paths_tsets(exported_deps))
|
||||
transitive_swiftmodules = ctx.actions.tset(SwiftmodulePathsTSet, value = output_module, children = _get_transitive_swift_paths_tsets(all_deps))
|
||||
else:
|
||||
exported_swiftmodules = ctx.actions.tset(SwiftmodulePathsTSet, children = _get_swift_paths_tsets(exported_deps))
|
||||
transitive_swiftmodules = ctx.actions.tset(SwiftmodulePathsTSet, children = _get_transitive_swift_paths_tsets(all_deps))
|
||||
|
||||
return SwiftDependencyInfo(
|
||||
exported_headers = _get_exported_headers_tset(ctx, exported_headers),
|
||||
exported_swiftmodule_paths = exported_swiftmodules,
|
||||
transitive_swiftmodule_paths = transitive_swiftmodules,
|
||||
)
|
||||
|
||||
def _header_basename(header: ["artifact", "string"]) -> "string":
|
||||
if type(header) == type(""):
|
||||
return paths.basename(header)
|
||||
else:
|
||||
return header.basename
|
||||
|
||||
def _uses_explicit_modules(ctx: "context") -> bool.type:
|
||||
swift_toolchain = ctx.attrs._apple_toolchain[AppleToolchainInfo].swift_toolchain_info
|
||||
return ctx.attrs.uses_explicit_modules and is_sdk_modules_provided(swift_toolchain)
|
||||
40
vendor/cxx/tools/buck/prelude/apple/swift_module_map.bzl
vendored
Normal file
40
vendor/cxx/tools/buck/prelude/apple/swift_module_map.bzl
vendored
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
def write_swift_module_map(
|
||||
ctx: "context",
|
||||
module_name: str.type,
|
||||
sdk_deps: ["SdkCompiledModuleInfo"]) -> "artifact":
|
||||
return write_swift_module_map_with_swift_deps(ctx, module_name, sdk_deps, [])
|
||||
|
||||
def write_swift_module_map_with_swift_deps(
|
||||
ctx: "context",
|
||||
module_name: str.type,
|
||||
sdk_swift_deps: ["SdkCompiledModuleInfo"],
|
||||
swift_deps: ["artifact"]) -> "artifact":
|
||||
deps = {}
|
||||
for sdk_dep in sdk_swift_deps:
|
||||
if sdk_dep.is_swiftmodule:
|
||||
deps[sdk_dep.module_name] = {
|
||||
"isFramework": sdk_dep.is_framework,
|
||||
"moduleName": sdk_dep.module_name,
|
||||
"modulePath": sdk_dep.output_artifact,
|
||||
}
|
||||
|
||||
for swift_dep in swift_deps:
|
||||
# The swiftmodule filename always matches the module name
|
||||
name = swift_dep.basename[:-12]
|
||||
deps[name] = {
|
||||
"isFramework": False,
|
||||
"moduleName": name,
|
||||
"modulePath": swift_dep,
|
||||
}
|
||||
|
||||
return ctx.actions.write_json(
|
||||
module_name + ".swift_module_map.json",
|
||||
deps.values(),
|
||||
)
|
||||
240
vendor/cxx/tools/buck/prelude/apple/swift_pcm_compilation.bzl
vendored
Normal file
240
vendor/cxx/tools/buck/prelude/apple/swift_pcm_compilation.bzl
vendored
Normal file
|
|
@ -0,0 +1,240 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load(":apple_sdk_modules_utility.bzl", "get_sdk_deps_tset")
|
||||
load(":apple_toolchain_types.bzl", "AppleToolchainInfo")
|
||||
load(":apple_utility.bzl", "expand_relative_prefixed_sdk_path", "get_disable_pch_validation_flags", "get_module_name", "get_versioned_target_triple")
|
||||
load(":swift_pcm_compilation_types.bzl", "SwiftPCMCompilationInfo")
|
||||
load(":swift_toolchain_types.bzl", "SdkCompiledModuleInfo")
|
||||
|
||||
_REQUIRED_SDK_MODULES = ["Foundation"]
|
||||
|
||||
def _project_as_clang_deps(value: "SwiftPCMCompilationInfo"):
|
||||
return [
|
||||
"-Xcc",
|
||||
cmd_args(["-fmodule-file=", value.name, "=", value.pcm_output], delimiter = ""),
|
||||
"-Xcc",
|
||||
cmd_args(["-fmodule-map-file=", value.exported_pre.modulemap_path], delimiter = ""),
|
||||
"-Xcc",
|
||||
] + value.exported_pre.args
|
||||
|
||||
PcmDepTSet = transitive_set(args_projections = {
|
||||
"clang_deps": _project_as_clang_deps,
|
||||
})
|
||||
|
||||
def get_pcm_deps_tset(ctx: "context", deps: ["dependency"]) -> "PcmDepTSet":
|
||||
pcm_deps = [
|
||||
ctx.actions.tset(
|
||||
PcmDepTSet,
|
||||
value = d[SwiftPCMCompilationInfo],
|
||||
children = [d[SwiftPCMCompilationInfo].deps_set],
|
||||
)
|
||||
for d in deps
|
||||
if SwiftPCMCompilationInfo in d
|
||||
]
|
||||
return ctx.actions.tset(PcmDepTSet, children = pcm_deps)
|
||||
|
||||
def compile_swift_sdk_pcm(
|
||||
ctx: "context",
|
||||
toolchain_context: struct.type,
|
||||
sdk_deps_set: "SDKDepTSet",
|
||||
uncompiled_sdk_module_info: "SdkUncompiledModuleInfo",
|
||||
sdk_module_providers: {str.type: "SdkCompiledModuleInfo"}):
|
||||
module_name = uncompiled_sdk_module_info.module_name
|
||||
|
||||
cmd = cmd_args(toolchain_context.compiler)
|
||||
cmd.add(uncompiled_sdk_module_info.partial_cmd)
|
||||
cmd.add(["-sdk", toolchain_context.sdk_path])
|
||||
cmd.add(toolchain_context.compiler_flags)
|
||||
|
||||
if toolchain_context.swift_resource_dir:
|
||||
cmd.add([
|
||||
"-resource-dir",
|
||||
toolchain_context.swift_resource_dir,
|
||||
])
|
||||
|
||||
cmd.add(sdk_deps_set.project_as_args("clang_deps"))
|
||||
|
||||
expanded_modulemap_path_cmd = expand_relative_prefixed_sdk_path(
|
||||
cmd_args(toolchain_context.sdk_path),
|
||||
cmd_args(toolchain_context.swift_resource_dir),
|
||||
uncompiled_sdk_module_info.input_relative_path,
|
||||
)
|
||||
pcm_output = ctx.actions.declare_output(module_name + ".pcm")
|
||||
cmd.add([
|
||||
"-o",
|
||||
pcm_output.as_output(),
|
||||
expanded_modulemap_path_cmd,
|
||||
])
|
||||
|
||||
# For SDK modules we need to set a few more args
|
||||
cmd.add([
|
||||
"-Xcc",
|
||||
"-Xclang",
|
||||
"-Xcc",
|
||||
"-emit-module",
|
||||
"-Xcc",
|
||||
"-Xclang",
|
||||
"-Xcc",
|
||||
"-fsystem-module",
|
||||
])
|
||||
|
||||
_add_sdk_module_search_path(cmd, uncompiled_sdk_module_info, toolchain_context)
|
||||
|
||||
sdk_module_providers[uncompiled_sdk_module_info.name] = SdkCompiledModuleInfo(
|
||||
name = uncompiled_sdk_module_info.name,
|
||||
module_name = module_name,
|
||||
is_framework = uncompiled_sdk_module_info.is_framework,
|
||||
output_artifact = pcm_output,
|
||||
is_swiftmodule = False,
|
||||
deps = sdk_deps_set,
|
||||
input_relative_path = expanded_modulemap_path_cmd,
|
||||
)
|
||||
|
||||
ctx.actions.run(cmd, category = "sdk_swift_pcm_compile", identifier = module_name)
|
||||
|
||||
def compile_swift_pcm(
|
||||
ctx: "context",
|
||||
exported_pre: "CPreprocessor",
|
||||
propagated_exported_preprocessor_info: ["CPreprocessorInfo", None]) -> ["SwiftPCMCompilationInfo", None]:
|
||||
module_name = get_module_name(ctx)
|
||||
modulemap_path = exported_pre.modulemap_path
|
||||
|
||||
toolchain = ctx.attrs._apple_toolchain[AppleToolchainInfo].swift_toolchain_info
|
||||
cmd = cmd_args(toolchain.compiler)
|
||||
cmd.add(get_shared_pcm_compilation_args(get_versioned_target_triple(ctx), module_name))
|
||||
cmd.add(["-sdk", toolchain.sdk_path])
|
||||
cmd.add(toolchain.compiler_flags)
|
||||
|
||||
sdk_deps_tset = get_sdk_deps_tset(
|
||||
ctx,
|
||||
module_name,
|
||||
ctx.attrs.exported_deps,
|
||||
_REQUIRED_SDK_MODULES,
|
||||
toolchain,
|
||||
)
|
||||
cmd.add(sdk_deps_tset.project_as_args("clang_deps"))
|
||||
|
||||
if toolchain.resource_dir:
|
||||
cmd.add([
|
||||
"-resource-dir",
|
||||
toolchain.resource_dir,
|
||||
])
|
||||
|
||||
# To compile a pcm we only use the exported_deps as those are the only
|
||||
# ones that should be transitively exported through public headers
|
||||
pcm_deps_tset = get_pcm_deps_tset(ctx, ctx.attrs.exported_deps)
|
||||
cmd.add(pcm_deps_tset.project_as_args("clang_deps"))
|
||||
|
||||
pcm_output = ctx.actions.declare_output(module_name + ".pcm")
|
||||
cmd.add([
|
||||
"-o",
|
||||
pcm_output.as_output(),
|
||||
modulemap_path,
|
||||
])
|
||||
|
||||
# To correctly resolve modulemap's headers,
|
||||
# a search path to the root of modulemap should be passed.
|
||||
cmd.add([
|
||||
"-Xcc",
|
||||
"-I",
|
||||
"-Xcc",
|
||||
cmd_args(modulemap_path).parent(),
|
||||
])
|
||||
|
||||
# When compiling pcm files, module's exported pps and inherited pps
|
||||
# must be provided to an action like hmaps which are used for headers resolution.
|
||||
if propagated_exported_preprocessor_info:
|
||||
cmd.add(cmd_args(propagated_exported_preprocessor_info.set.project_as_args("args"), prepend = "-Xcc"))
|
||||
|
||||
ctx.actions.run(cmd, category = "swift_pcm_compile", identifier = module_name)
|
||||
|
||||
return SwiftPCMCompilationInfo(
|
||||
name = module_name,
|
||||
pcm_output = pcm_output,
|
||||
exported_pre = exported_pre,
|
||||
deps_set = ctx.actions.tset(
|
||||
PcmDepTSet,
|
||||
children = [pcm_deps_tset],
|
||||
),
|
||||
sdk_deps_set = sdk_deps_tset,
|
||||
)
|
||||
|
||||
def get_shared_pcm_compilation_args(target: str.type, module_name: str.type) -> "cmd_args":
|
||||
cmd = cmd_args()
|
||||
cmd.add([
|
||||
"-emit-pcm",
|
||||
"-target",
|
||||
target,
|
||||
"-module-name",
|
||||
module_name,
|
||||
"-Xfrontend",
|
||||
"-disable-implicit-swift-modules",
|
||||
"-Xcc",
|
||||
"-fno-implicit-modules",
|
||||
"-Xcc",
|
||||
"-fno-implicit-module-maps",
|
||||
# Disable debug info in pcm files. This is required to avoid embedding absolute paths
|
||||
# and ending up with mismatched pcm file sizes.
|
||||
"-Xcc",
|
||||
"-Xclang",
|
||||
"-Xcc",
|
||||
"-fmodule-format=raw",
|
||||
# Embed all input files into the PCM so we don't need to include module map files when
|
||||
# building remotely.
|
||||
# https://github.com/apple/llvm-project/commit/fb1e7f7d1aca7bcfc341e9214bda8b554f5ae9b6
|
||||
"-Xcc",
|
||||
"-Xclang",
|
||||
"-Xcc",
|
||||
"-fmodules-embed-all-files",
|
||||
# Embed all files that were read during compilation into the generated PCM.
|
||||
"-Xcc",
|
||||
"-Xclang",
|
||||
"-Xcc",
|
||||
"-fmodule-file-home-is-cwd",
|
||||
# Once we have an empty working directory the compiler provided headers such as float.h
|
||||
# cannot be found, so add . to the header search paths.
|
||||
"-Xcc",
|
||||
"-I.",
|
||||
])
|
||||
|
||||
cmd.add(get_disable_pch_validation_flags())
|
||||
|
||||
return cmd
|
||||
|
||||
def _remove_path_components_from_right(path: str.type, count: int.type):
|
||||
path_components = path.split("/")
|
||||
removed_path = "/".join(path_components[0:-count])
|
||||
return removed_path
|
||||
|
||||
def _add_sdk_module_search_path(cmd, uncompiled_sdk_module_info, toolchain_context):
|
||||
modulemap_path = uncompiled_sdk_module_info.input_relative_path
|
||||
|
||||
# If this input is a framework we need to search above the
|
||||
# current framework location, otherwise we include the
|
||||
# modulemap root.
|
||||
if uncompiled_sdk_module_info.is_framework:
|
||||
frameworks_dir_path = _remove_path_components_from_right(modulemap_path, 3)
|
||||
expanded_path = expand_relative_prefixed_sdk_path(
|
||||
cmd_args(toolchain_context.sdk_path),
|
||||
cmd_args(toolchain_context.swift_resource_dir),
|
||||
frameworks_dir_path,
|
||||
)
|
||||
else:
|
||||
module_root_path = _remove_path_components_from_right(modulemap_path, 1)
|
||||
expanded_path = expand_relative_prefixed_sdk_path(
|
||||
cmd_args(toolchain_context.sdk_path),
|
||||
cmd_args(toolchain_context.swift_resource_dir),
|
||||
module_root_path,
|
||||
)
|
||||
|
||||
cmd.add([
|
||||
"-Xcc",
|
||||
("-F" if uncompiled_sdk_module_info.is_framework else "-I"),
|
||||
"-Xcc",
|
||||
cmd_args(expanded_path),
|
||||
])
|
||||
14
vendor/cxx/tools/buck/prelude/apple/swift_pcm_compilation_types.bzl
vendored
Normal file
14
vendor/cxx/tools/buck/prelude/apple/swift_pcm_compilation_types.bzl
vendored
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
SwiftPCMCompilationInfo = provider(fields = [
|
||||
"name",
|
||||
"pcm_output",
|
||||
"exported_pre",
|
||||
"deps_set",
|
||||
"sdk_deps_set", # A TSet of direct and transitive SDK deps.
|
||||
])
|
||||
65
vendor/cxx/tools/buck/prelude/apple/swift_toolchain.bzl
vendored
Normal file
65
vendor/cxx/tools/buck/prelude/apple/swift_toolchain.bzl
vendored
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load(":apple_sdk_module.bzl", "create_sdk_modules_graph")
|
||||
load(":swift_toolchain_types.bzl", "SdkUncompiledModuleInfo", "SwiftToolchainInfo")
|
||||
|
||||
def swift_toolchain_impl(ctx):
|
||||
compiler = cmd_args(ctx.attrs._swiftc_wrapper[RunInfo]).add(ctx.attrs.swiftc[RunInfo])
|
||||
compiler_flags = ctx.attrs.swiftc_flags
|
||||
sdk_path = ctx.attrs._internal_sdk_path or ctx.attrs.sdk_path
|
||||
resource_dir = ctx.attrs.resource_dir
|
||||
|
||||
toolchain_context = struct(
|
||||
compiler = compiler,
|
||||
sdk_path = sdk_path,
|
||||
compiler_flags = compiler_flags,
|
||||
swift_resource_dir = resource_dir,
|
||||
)
|
||||
|
||||
compiled_sdk_module_providers = {}
|
||||
|
||||
sdk_uncompiled_module_infos = filter(None, [d.get(SdkUncompiledModuleInfo) for d in ctx.attrs.sdk_modules])
|
||||
for uncompiled_swift_module_info in sdk_uncompiled_module_infos:
|
||||
create_sdk_modules_graph(
|
||||
ctx,
|
||||
compiled_sdk_module_providers,
|
||||
uncompiled_swift_module_info,
|
||||
toolchain_context,
|
||||
)
|
||||
|
||||
compiled_sdk_swift_module_providers = {
|
||||
info.module_name: info
|
||||
for _, info in compiled_sdk_module_providers.items()
|
||||
if info.is_swiftmodule
|
||||
}
|
||||
|
||||
compiled_sdk_clang_module_providers = {
|
||||
info.module_name: info
|
||||
for _, info in compiled_sdk_module_providers.items()
|
||||
if not info.is_swiftmodule
|
||||
}
|
||||
|
||||
return [
|
||||
DefaultInfo(),
|
||||
SwiftToolchainInfo(
|
||||
architecture = ctx.attrs.architecture,
|
||||
can_toolchain_emit_obj_c_header_textually = ctx.attrs.can_toolchain_emit_obj_c_header_textually,
|
||||
# TODO(T99038725): until we add -debug-compilation-dir we need to wrap
|
||||
# the Swift invocations so that we can apply a debug prefix map for
|
||||
# the current directory while maintaining cache hit.
|
||||
compiled_sdk_clang_modules = compiled_sdk_clang_module_providers,
|
||||
compiled_sdk_swift_modules = compiled_sdk_swift_module_providers,
|
||||
compiler = compiler,
|
||||
compiler_flags = compiler_flags,
|
||||
prefix_serialized_debugging_options = ctx.attrs.prefix_serialized_debug_info,
|
||||
resource_dir = resource_dir,
|
||||
sdk_path = sdk_path,
|
||||
swift_stdlib_tool = ctx.attrs.swift_stdlib_tool[RunInfo],
|
||||
swift_stdlib_tool_flags = ctx.attrs.swift_stdlib_tool_flags,
|
||||
),
|
||||
]
|
||||
46
vendor/cxx/tools/buck/prelude/apple/swift_toolchain_types.bzl
vendored
Normal file
46
vendor/cxx/tools/buck/prelude/apple/swift_toolchain_types.bzl
vendored
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
#####################################################################
|
||||
# Providers
|
||||
|
||||
SwiftToolchainInfo = provider(fields = [
|
||||
"architecture",
|
||||
"can_toolchain_emit_obj_c_header_textually", # bool
|
||||
"compiled_sdk_clang_modules", # {str.type: SdkCompiledModuleInfo} Expose providers of compiled Clang SDK modules.
|
||||
"compiled_sdk_swift_modules", # {str.type: SdkCompiledModuleInfo} Expose providers of compiled Swift SDK modules.
|
||||
"compiler_flags",
|
||||
"compiler",
|
||||
"prefix_serialized_debugging_options", # bool
|
||||
"resource_dir", # "artifact",
|
||||
"sdk_path",
|
||||
"swift_stdlib_tool_flags",
|
||||
"swift_stdlib_tool",
|
||||
])
|
||||
|
||||
# A provider that represents a non-yet-compiled SDK (Swift or Clang) module,
|
||||
# and doesn't contain any artifacts because Swift toolchain isn't resolved yet.
|
||||
SdkUncompiledModuleInfo = provider(fields = [
|
||||
"name", # A name of a module with `.swift`/`.clang` suffix.
|
||||
"module_name", # A real name of a module, without distinguishing suffixes.
|
||||
"is_framework", # This is mostly needed for the generated Swift module map file.
|
||||
"is_swiftmodule", # If True then represents a swiftinterface, otherwise Clang's modulemap.
|
||||
"partial_cmd", # Partial arguments, required to compile a particular SDK module.
|
||||
"input_relative_path", # A relative prefixed path to a textual swiftinterface/modulemap file within an SDK.
|
||||
"deps", # [SdkUncompiledModuleInfo]
|
||||
])
|
||||
|
||||
# A provider that represents an already-compiled SDK (Swift or Clang) module.
|
||||
SdkCompiledModuleInfo = provider(fields = [
|
||||
"name", # A name of a module with `.swift`/`.clang` suffix.
|
||||
"module_name", # A real name of a module, without distinguishing suffixes.
|
||||
"is_swiftmodule", # If True then contains a compiled swiftmodule, otherwise Clang's pcm.
|
||||
"is_framework",
|
||||
"output_artifact", # Compiled artifact either swiftmodule or pcm.
|
||||
"input_relative_path",
|
||||
"deps", # A TSet of [SdkCompiledModuleInfo]
|
||||
])
|
||||
30
vendor/cxx/tools/buck/prelude/apple/tools/TARGETS.v2
vendored
Normal file
30
vendor/cxx/tools/buck/prelude/apple/tools/TARGETS.v2
vendored
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
prelude = native
|
||||
|
||||
prelude.python_bootstrap_binary(
|
||||
name = "make_modulemap",
|
||||
main = "make_modulemap.py",
|
||||
visibility = ["PUBLIC"],
|
||||
)
|
||||
|
||||
prelude.export_file(
|
||||
name = "swift_exec.sh",
|
||||
src = "swift_exec.sh",
|
||||
)
|
||||
|
||||
prelude.command_alias(
|
||||
name = "swift_exec",
|
||||
exe = ":swift_exec.sh",
|
||||
visibility = ["PUBLIC"],
|
||||
)
|
||||
|
||||
prelude.python_bootstrap_binary(
|
||||
name = "make_vfsoverlay",
|
||||
main = "make_vfsoverlay.py",
|
||||
visibility = ["PUBLIC"],
|
||||
)
|
||||
|
||||
prelude.python_bootstrap_binary(
|
||||
name = "swift_objc_header_postprocess",
|
||||
main = "swift_objc_header_postprocess.py",
|
||||
visibility = ["PUBLIC"],
|
||||
)
|
||||
154
vendor/cxx/tools/buck/prelude/apple/tools/make_modulemap.py
vendored
Normal file
154
vendor/cxx/tools/buck/prelude/apple/tools/make_modulemap.py
vendored
Normal file
|
|
@ -0,0 +1,154 @@
|
|||
#!/usr/bin/env python3
|
||||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import re
|
||||
from io import TextIOWrapper
|
||||
from typing import Dict, Iterable, List
|
||||
|
||||
|
||||
class Module:
|
||||
def __init__(self, name: str) -> None:
|
||||
self.name: str = name
|
||||
self.headers: List[str] = []
|
||||
self.submodules: Dict[str, Module] = {}
|
||||
|
||||
def add_header(self, src: str) -> None:
|
||||
self.headers.append(src)
|
||||
|
||||
def get_submodule(self, name: str) -> "Module":
|
||||
if name not in self.submodules:
|
||||
self.submodules[name] = Module(name)
|
||||
|
||||
return self.submodules[name]
|
||||
|
||||
def render(self, f: TextIOWrapper, path_prefix: str, indent: int = 0) -> None:
|
||||
space = " " * indent
|
||||
f.write(f"{space}module {self.name} {{\n")
|
||||
|
||||
submodule_names = set()
|
||||
for submodule_name in sorted(self.submodules.keys()):
|
||||
submodule = self.submodules[submodule_name]
|
||||
|
||||
# remove any extensions for readibility
|
||||
sanitized_name = os.path.splitext(submodule_name)[0]
|
||||
|
||||
# module names can only be ascii or _
|
||||
sanitized_name = re.sub(r"[^A-Za-z0-9_]", "_", sanitized_name)
|
||||
if sanitized_name[0].isdigit():
|
||||
sanitized_name = "_" + sanitized_name
|
||||
|
||||
# avoid any collisions with other files
|
||||
while sanitized_name in submodule_names:
|
||||
sanitized_name += "_"
|
||||
|
||||
submodule_names.add(sanitized_name)
|
||||
submodule.name = sanitized_name
|
||||
submodule.render(f, path_prefix, indent + 4)
|
||||
|
||||
header_space = " " * (indent + 4)
|
||||
for h in sorted(self.headers):
|
||||
f.write(f'{header_space}header "{os.path.join(path_prefix, h)}"\n')
|
||||
|
||||
if self.headers:
|
||||
f.write(f"{header_space}export *\n")
|
||||
|
||||
f.write(f"{space}}}\n")
|
||||
|
||||
|
||||
def _write_single_module(
|
||||
f: TextIOWrapper, name: str, headers: Iterable[str], path_prefix: str
|
||||
) -> None:
|
||||
module = Module(name)
|
||||
for h in headers:
|
||||
module.add_header(h)
|
||||
|
||||
module.render(f, path_prefix)
|
||||
|
||||
|
||||
def _write_submodules(
|
||||
f: TextIOWrapper, name: str, headers: Iterable[str], path_prefix: str
|
||||
) -> None:
|
||||
# Create a tree of nested modules, one for each path component.
|
||||
root_module = Module(name)
|
||||
for h in headers:
|
||||
module = root_module
|
||||
for i, component in enumerate(h.split(os.sep)):
|
||||
if i == 0 and component == name:
|
||||
# The common case is we have a singe header path prefix that matches the module name.
|
||||
# In this case we add the headers directly to the root module.
|
||||
pass
|
||||
else:
|
||||
module = module.get_submodule(component)
|
||||
|
||||
module.add_header(h)
|
||||
|
||||
root_module.render(f, path_prefix)
|
||||
|
||||
|
||||
def _write_swift_header(f: TextIOWrapper, name: str, swift_header_path: str) -> None:
|
||||
f.write(
|
||||
f"""
|
||||
module {name}.Swift {{
|
||||
header "{swift_header_path}"
|
||||
requires objc
|
||||
}}
|
||||
"""
|
||||
)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument(
|
||||
"--output", required=True, help="The path to write the modulemap to"
|
||||
)
|
||||
parser.add_argument("--name", required=True, help="The name of the module")
|
||||
parser.add_argument(
|
||||
"--swift-header", help="If this is a mixed module extend with this Swift header"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--use-submodules",
|
||||
action="store_true",
|
||||
help="If set produce a modulemap with per-header submodules",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--symlink-tree",
|
||||
required=True,
|
||||
)
|
||||
parser.add_argument(
|
||||
"mappings", nargs="*", default=[], help="A list of import paths"
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
output_dir = os.path.dirname(args.output)
|
||||
path_prefix = os.path.relpath(args.symlink_tree, output_dir)
|
||||
|
||||
with open(args.output, "w") as f:
|
||||
if args.use_submodules:
|
||||
# pyre-fixme[6]: For 4th param expected `str` but got `bytes`.
|
||||
_write_submodules(f, args.name, args.mappings, path_prefix)
|
||||
else:
|
||||
# pyre-fixme[6]: For 4th param expected `str` but got `bytes`.
|
||||
_write_single_module(f, args.name, args.mappings, path_prefix)
|
||||
|
||||
if args.swift_header:
|
||||
swift_header_name = os.path.relpath(args.swift_header, output_dir)
|
||||
_write_swift_header(
|
||||
f,
|
||||
args.name,
|
||||
os.path.join(
|
||||
"swift-extended_symlink_tree",
|
||||
args.name,
|
||||
str(swift_header_name),
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
95
vendor/cxx/tools/buck/prelude/apple/tools/make_vfsoverlay.py
vendored
Normal file
95
vendor/cxx/tools/buck/prelude/apple/tools/make_vfsoverlay.py
vendored
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
#!/usr/bin/env fbpython
|
||||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
import argparse
|
||||
import itertools
|
||||
import json
|
||||
import os
|
||||
from typing import Dict, List, Tuple, TypedDict
|
||||
|
||||
# Example VFS overlay in JSON format
|
||||
# ----------------------------------
|
||||
# {
|
||||
# 'version': 0,
|
||||
# 'roots': [
|
||||
# { 'name': 'OUT_DIR', 'type': 'directory',
|
||||
# 'contents': [
|
||||
# { 'name': 'module.map', 'type': 'file',
|
||||
# 'external-contents': 'INPUT_DIR/actual_module2.map'
|
||||
# }
|
||||
# ]
|
||||
# }
|
||||
# ]
|
||||
# }
|
||||
|
||||
|
||||
class OverlayRoot(TypedDict):
|
||||
name: str
|
||||
type: str
|
||||
contents: List[Dict[str, str]]
|
||||
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument(
|
||||
"--output", required=True, help="The path to write the VFS overlay to"
|
||||
)
|
||||
parser.add_argument(
|
||||
"mappings", nargs="*", default=[], help="A list of virtual paths to real paths"
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
if len(args.mappings) % 2 != 0:
|
||||
parser.error("mappings must be dest-source pairs")
|
||||
|
||||
# Group the mappings by containing directory
|
||||
mappings: Dict[str, List[Tuple[str, str]]] = {}
|
||||
for src, dst in itertools.zip_longest(*([iter(args.mappings)] * 2)):
|
||||
folder, basename = os.path.split(src)
|
||||
mappings.setdefault(folder, []).append((basename, dst))
|
||||
|
||||
with open(args.output, "w") as f:
|
||||
json.dump(
|
||||
{
|
||||
"version": 0,
|
||||
"roots": _get_roots(mappings),
|
||||
},
|
||||
f,
|
||||
sort_keys=True,
|
||||
indent=4,
|
||||
)
|
||||
f.write("\n")
|
||||
f.flush()
|
||||
|
||||
|
||||
def _get_roots(mappings: Dict[str, List[Tuple[str, str]]]) -> List[OverlayRoot]:
|
||||
roots = []
|
||||
for folder, file_maps in mappings.items():
|
||||
contents = []
|
||||
for src, dst in file_maps:
|
||||
contents.append(
|
||||
{
|
||||
"name": src,
|
||||
"type": "file",
|
||||
"external-contents": dst,
|
||||
}
|
||||
)
|
||||
|
||||
roots.append(
|
||||
{
|
||||
"name": folder,
|
||||
"type": "directory",
|
||||
"contents": contents,
|
||||
}
|
||||
)
|
||||
|
||||
return roots
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
26
vendor/cxx/tools/buck/prelude/apple/tools/swift_exec.sh
vendored
Normal file
26
vendor/cxx/tools/buck/prelude/apple/tools/swift_exec.sh
vendored
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
#!/bin/bash
|
||||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
# - Apply a debug prefix map for the current directory
|
||||
# to make debug info relocatable.
|
||||
# - Use $TMPDIR for the module cache location. This
|
||||
# will be set to a unique location for each RE action
|
||||
# which will avoid sharing modules across RE actions.
|
||||
# This is necessary as the inputs to the modules will
|
||||
# be transient and can be removed at any point, causing
|
||||
# module validation errors to fail builds.
|
||||
if [ -n "$INSIDE_RE_WORKER" ]; then
|
||||
MODULE_CACHE_PATH="$TMPDIR/module-cache"
|
||||
else
|
||||
# When building locally we can use a shared module
|
||||
# cache as the inputs should remain at a fixed
|
||||
# location.
|
||||
MODULE_CACHE_PATH="/tmp/buck-module-cache"
|
||||
fi
|
||||
|
||||
exec "$@" -debug-prefix-map "$PWD"=. -module-cache-path "$MODULE_CACHE_PATH"
|
||||
307
vendor/cxx/tools/buck/prelude/apple/tools/swift_objc_header_postprocess.py
vendored
Normal file
307
vendor/cxx/tools/buck/prelude/apple/tools/swift_objc_header_postprocess.py
vendored
Normal file
|
|
@ -0,0 +1,307 @@
|
|||
#!/usr/bin/env fbpython
|
||||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
from typing import Dict, Iterable, TextIO
|
||||
|
||||
# Out-of-date? Update with this command:
|
||||
#
|
||||
# xcode-select --print-path | xargs printf '%s/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/System/Library/Frameworks/' | xargs ls | rg '^([A-Z].+)\.framework$' -r '${1}' | xargs printf ' "%s",\n' && xcode-select --print-path | xargs printf '%s/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/usr/include/module.modulemap' | xargs cat | rg '^module ([a-zA-Z0-9_]*) .*$' -r '${1}'| xargs printf ' "%s",\n'
|
||||
APPLE_SYSTEM_MODULES = {
|
||||
"ARKit",
|
||||
"AVFAudio",
|
||||
"AVFoundation",
|
||||
"AVKit",
|
||||
"Accelerate",
|
||||
"Accessibility",
|
||||
"Accounts",
|
||||
"AdServices",
|
||||
"AdSupport",
|
||||
"AddressBook",
|
||||
"AddressBookUI",
|
||||
"AppClip",
|
||||
"AppTrackingTransparency",
|
||||
"AssetsLibrary",
|
||||
"AudioToolbox",
|
||||
"AudioUnit",
|
||||
"AuthenticationServices",
|
||||
"AutomaticAssessmentConfiguration",
|
||||
"BackgroundTasks",
|
||||
"BusinessChat",
|
||||
"CFNetwork",
|
||||
"CallKit",
|
||||
"CarPlay",
|
||||
"ClassKit",
|
||||
"ClockKit",
|
||||
"CloudKit",
|
||||
"Combine",
|
||||
"Contacts",
|
||||
"ContactsUI",
|
||||
"CoreAudio",
|
||||
"CoreAudioKit",
|
||||
"CoreAudioTypes",
|
||||
"CoreBluetooth",
|
||||
"CoreData",
|
||||
"CoreFoundation",
|
||||
"CoreGraphics",
|
||||
"CoreHaptics",
|
||||
"CoreImage",
|
||||
"CoreLocation",
|
||||
"CoreLocationUI",
|
||||
"CoreMIDI",
|
||||
"CoreML",
|
||||
"CoreMedia",
|
||||
"CoreMotion",
|
||||
"CoreNFC",
|
||||
"CoreServices",
|
||||
"CoreSpotlight",
|
||||
"CoreTelephony",
|
||||
"CoreText",
|
||||
"CoreVideo",
|
||||
"CryptoKit",
|
||||
"CryptoTokenKit",
|
||||
"DataDetection",
|
||||
"DeveloperToolsSupport",
|
||||
"DeviceActivity",
|
||||
"DeviceCheck",
|
||||
"EventKit",
|
||||
"EventKitUI",
|
||||
"ExposureNotification",
|
||||
"ExternalAccessory",
|
||||
"FamilyControls",
|
||||
"FileProvider",
|
||||
"FileProviderUI",
|
||||
"Foundation",
|
||||
"GLKit",
|
||||
"GSS",
|
||||
"GameController",
|
||||
"GameKit",
|
||||
"GameplayKit",
|
||||
"GroupActivities",
|
||||
"HealthKit",
|
||||
"HealthKitUI",
|
||||
"HomeKit",
|
||||
"IOKit",
|
||||
"IOSurface",
|
||||
"IdentityLookup",
|
||||
"IdentityLookupUI",
|
||||
"ImageCaptureCore",
|
||||
"ImageIO",
|
||||
"Intents",
|
||||
"IntentsUI",
|
||||
"JavaScriptCore",
|
||||
"LinkPresentation",
|
||||
"LocalAuthentication",
|
||||
"ManagedSettings",
|
||||
"ManagedSettingsUI",
|
||||
"MapKit",
|
||||
"MediaAccessibility",
|
||||
"MediaPlayer",
|
||||
"MediaToolbox",
|
||||
"MessageUI",
|
||||
"Messages",
|
||||
"Metal",
|
||||
"MetalKit",
|
||||
"MetalPerformanceShaders",
|
||||
"MetalPerformanceShadersGraph",
|
||||
"MetricKit",
|
||||
"MobileCoreServices",
|
||||
"ModelIO",
|
||||
"MultipeerConnectivity",
|
||||
"MusicKit",
|
||||
"NaturalLanguage",
|
||||
"NearbyInteraction",
|
||||
"Network",
|
||||
"NetworkExtension",
|
||||
"NewsstandKit",
|
||||
"NotificationCenter",
|
||||
"OSLog",
|
||||
"OpenAL",
|
||||
"OpenGLES",
|
||||
"PDFKit",
|
||||
"PHASE",
|
||||
"PassKit",
|
||||
"PencilKit",
|
||||
"Photos",
|
||||
"PhotosUI",
|
||||
"PushKit",
|
||||
"QuartzCore",
|
||||
"QuickLook",
|
||||
"QuickLookThumbnailing",
|
||||
"RealityFoundation",
|
||||
"RealityKit",
|
||||
"ReplayKit",
|
||||
"SafariServices",
|
||||
"SceneKit",
|
||||
"ScreenTime",
|
||||
"Security",
|
||||
"SensorKit",
|
||||
"ShazamKit",
|
||||
"Social",
|
||||
"SoundAnalysis",
|
||||
"Speech",
|
||||
"SpriteKit",
|
||||
"StoreKit",
|
||||
"SwiftUI",
|
||||
"SystemConfiguration",
|
||||
"TabularData",
|
||||
"Twitter",
|
||||
"UIKit",
|
||||
"UniformTypeIdentifiers",
|
||||
"UserNotifications",
|
||||
"UserNotificationsUI",
|
||||
"VideoSubscriberAccount",
|
||||
"VideoToolbox",
|
||||
"Vision",
|
||||
"VisionKit",
|
||||
"WatchConnectivity",
|
||||
"WebKit",
|
||||
"WidgetKit",
|
||||
"AppleTextureEncoder",
|
||||
"Compression",
|
||||
"Darwin",
|
||||
"asl",
|
||||
"dnssd",
|
||||
"os",
|
||||
"os_object",
|
||||
"os_workgroup",
|
||||
"libkern",
|
||||
"notify",
|
||||
"zlib",
|
||||
"SQLite3",
|
||||
}
|
||||
|
||||
APPLE_TEST_FRAMEWORKS = {
|
||||
"XCTest",
|
||||
}
|
||||
|
||||
|
||||
# These modules require specific handling, as they do not have an umbrella
|
||||
# header that matches the module name, as typical Apple frameworks do.
|
||||
APPLE_SYSTEM_MODULE_OVERRIDES = {
|
||||
"Dispatch": ("dispatch", ("dispatch.h",)),
|
||||
"ObjectiveC": ("objc", ("runtime.h",)),
|
||||
}
|
||||
|
||||
|
||||
def write_imports_for_headers(out: TextIO, prefix: str, headers: Iterable[str]) -> None:
|
||||
for header in headers:
|
||||
print(f"#import <{prefix}/{header}>", file=out)
|
||||
|
||||
|
||||
def write_imports_for_modules(
|
||||
out: TextIO,
|
||||
postprocessing_module_name: str,
|
||||
modules: Iterable[str],
|
||||
deps: Dict[str, Iterable[str]],
|
||||
) -> None:
|
||||
# We only include the traditional textual imports when modules are disabled, so
|
||||
# that the behavior with modules enabled is identical to the behavior without
|
||||
# the postprocessing.
|
||||
print("#else", file=out)
|
||||
for module in modules:
|
||||
if headers := deps.get(module):
|
||||
write_imports_for_headers(out, module, headers)
|
||||
elif override := APPLE_SYSTEM_MODULE_OVERRIDES.get(module):
|
||||
write_imports_for_headers(out, override[0], override[1])
|
||||
elif module in APPLE_SYSTEM_MODULES or module in APPLE_TEST_FRAMEWORKS:
|
||||
# When we don't have an explicit override for the module, we use the module's
|
||||
# name as an umbrella header. This is used for typical Apple frameworks like
|
||||
# Foundation and UIKit.
|
||||
write_imports_for_headers(out, module, (f"{module}.h",))
|
||||
else:
|
||||
print(
|
||||
f"""
|
||||
The module "{module}" was imported as a dependency of Swift code in "{postprocessing_module_name}", but could not be mapped to a list of header imports by Buck's Swift header postprocessing. There are two possibilities:
|
||||
|
||||
1. If "{module}" is an internal library, it is likely that the exported_deps of "{postprocessing_module_name}" are incorrect. Try fixing them manually or with "arc fixmydeps". This is the most likely issue.
|
||||
|
||||
2. If "{module}" is a system (Apple) framework, the list of Apple system modules in {os.path.basename(__file__)} is out-of-date. There is a command to fix it in that file. This issue is unlikely.
|
||||
""",
|
||||
file=sys.stderr,
|
||||
)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("header")
|
||||
parser.add_argument("deps")
|
||||
parser.add_argument("out")
|
||||
args = parser.parse_args()
|
||||
|
||||
with open(args.deps) as f:
|
||||
deps = json.load(f)
|
||||
|
||||
# Strips the suffix from the header name, leaving us with just the name
|
||||
# of the module that we are postprocessing the header for. This is used
|
||||
# for error reporting.
|
||||
postprocessing_module_name = os.path.basename(args.header).split("-")[0]
|
||||
|
||||
# The Swift compiler's output looks like this:
|
||||
#
|
||||
# #if __has_feature(modules)
|
||||
# #if __has_warning("-Watimport-in-framework-header")
|
||||
# #pragma clang diagnostic ignored "-Watimport-in-framework-header"
|
||||
# #endif
|
||||
# @import ModuleA;
|
||||
# @import ModuleB;
|
||||
# @import ModuleC;
|
||||
# #endif
|
||||
#
|
||||
# The implementation here balances being somewhat flexible to changes to the compiler's
|
||||
# output, unlikely though they may be, with avoiding adding too much complexity and getting
|
||||
# too close to implementing a full parser for Objective-C un-preprocessed header files.
|
||||
|
||||
with open(args.header) as header, open(args.out, "w") as out:
|
||||
# When this is None, it means that we are still searching for the start of the conditional
|
||||
# @import block in the generated header.
|
||||
modules = None
|
||||
# The Swift compiler emits an additional #if gate inside the conditional @import block, so
|
||||
# we need to track whether we're in a further nested conditional so that we know when the
|
||||
# main conditional block has ended.
|
||||
if_level = 0
|
||||
|
||||
for line in header:
|
||||
line = line.rstrip("\n")
|
||||
# When the modules has not been set, we are still searching for the start of the
|
||||
# modules @import section.
|
||||
if modules is None:
|
||||
if line == "#if __has_feature(modules)":
|
||||
modules = []
|
||||
if_level = 1
|
||||
else:
|
||||
if line.startswith("@import"):
|
||||
# Splitting on:
|
||||
# "@import ": to separate from the @import.
|
||||
# Semicolon and period: to separate the main module name from submodules or EOL.
|
||||
# The module name will then be the first item.
|
||||
modules.append(re.split(r"@import |[;.]", line)[1])
|
||||
elif line.startswith("#if"):
|
||||
# This allows us to handle the Clang diagnostic #if block that the compiler inserts
|
||||
# within the main #if block for modules.
|
||||
if_level += 1
|
||||
elif line.startswith("#endif"):
|
||||
if_level -= 1
|
||||
if if_level == 0:
|
||||
write_imports_for_modules(
|
||||
out,
|
||||
postprocessing_module_name,
|
||||
modules,
|
||||
deps,
|
||||
)
|
||||
modules = None
|
||||
print(line, file=out)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
52
vendor/cxx/tools/buck/prelude/apple/user/apple_resource_bundle.bzl
vendored
Normal file
52
vendor/cxx/tools/buck/prelude/apple/user/apple_resource_bundle.bzl
vendored
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load("@prelude//:attributes.bzl", "AppleBundleExtension")
|
||||
load("@prelude//apple:apple_bundle_resources.bzl", "get_apple_bundle_resource_part_list")
|
||||
load("@prelude//apple:apple_bundle_types.bzl", "AppleBundleResourceInfo")
|
||||
load("@prelude//apple:apple_toolchain_types.bzl", "AppleToolchainInfo", "AppleToolsInfo")
|
||||
load("@prelude//user:rule_spec.bzl", "RuleRegistrationSpec")
|
||||
load(":resource_group_map.bzl", "resource_group_map_attr")
|
||||
|
||||
def _get_apple_resources_toolchain_attr():
|
||||
# FIXME: prelude// should be standalone (not refer to fbcode//)
|
||||
return attrs.toolchain_dep(default = "fbcode//buck2/platform/toolchain:apple-resources", providers = [AppleToolchainInfo])
|
||||
|
||||
def _impl(ctx: "context") -> ["provider"]:
|
||||
resource_output = get_apple_bundle_resource_part_list(ctx)
|
||||
return [
|
||||
DefaultInfo(),
|
||||
AppleBundleResourceInfo(
|
||||
resource_output = resource_output,
|
||||
),
|
||||
]
|
||||
|
||||
registration_spec = RuleRegistrationSpec(
|
||||
name = "apple_resource_bundle",
|
||||
impl = _impl,
|
||||
attrs = {
|
||||
"asset_catalogs_compilation_options": attrs.dict(key = attrs.string(), value = attrs.any(), default = {}),
|
||||
"binary": attrs.option(attrs.dep(), default = None),
|
||||
"deps": attrs.list(attrs.dep(), default = []),
|
||||
"extension": attrs.one_of(attrs.enum(AppleBundleExtension), attrs.string()),
|
||||
"ibtool_flags": attrs.option(attrs.list(attrs.string()), default = None),
|
||||
"ibtool_module_flag": attrs.option(attrs.bool(), default = None),
|
||||
"info_plist": attrs.source(),
|
||||
"info_plist_substitutions": attrs.dict(key = attrs.string(), value = attrs.string(), sorted = False, default = {}),
|
||||
"product_name": attrs.option(attrs.string(), default = None),
|
||||
"resource_group": attrs.option(attrs.string(), default = None),
|
||||
"resource_group_map": resource_group_map_attr(),
|
||||
# Only include macOS hosted toolchains, so we compile resources directly on Mac RE
|
||||
"_apple_toolchain": _get_apple_resources_toolchain_attr(),
|
||||
# FIXME: prelude// should be standalone (not refer to fbsource//)
|
||||
"_apple_tools": attrs.exec_dep(default = "fbsource//xplat/buck2/platform/apple:apple-tools", providers = [AppleToolsInfo]),
|
||||
# Because `apple_resource_bundle` is a proxy for `apple_bundle`, we need to get `name`
|
||||
# field of the `apple_bundle`, as it's used as a fallback value in Info.plist.
|
||||
"_bundle_target_name": attrs.string(),
|
||||
"_compile_resources_locally_override": attrs.option(attrs.bool(), default = None),
|
||||
},
|
||||
)
|
||||
51
vendor/cxx/tools/buck/prelude/apple/user/apple_toolchain_override.bzl
vendored
Normal file
51
vendor/cxx/tools/buck/prelude/apple/user/apple_toolchain_override.bzl
vendored
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load("@prelude//apple:apple_toolchain_types.bzl", "AppleToolchainInfo")
|
||||
load("@prelude//cxx:cxx_toolchain_types.bzl", "CxxToolchainInfo")
|
||||
load("@prelude//user:rule_spec.bzl", "RuleRegistrationSpec")
|
||||
|
||||
def _impl(ctx: "context") -> ["provider"]:
|
||||
base = ctx.attrs.base[AppleToolchainInfo]
|
||||
cxx_toolchain_override = ctx.attrs.cxx_toolchain[CxxToolchainInfo]
|
||||
return [
|
||||
DefaultInfo(),
|
||||
AppleToolchainInfo(
|
||||
actool = base.actool,
|
||||
ibtool = base.ibtool,
|
||||
dsymutil = base.dsymutil,
|
||||
dwarfdump = base.dwarfdump,
|
||||
lipo = base.lipo,
|
||||
cxx_platform_info = base.cxx_platform_info,
|
||||
cxx_toolchain_info = cxx_toolchain_override if cxx_toolchain_override != None else base.cxx_toolchain_info,
|
||||
codesign = base.codesign,
|
||||
codesign_allocate = base.codesign_allocate,
|
||||
compile_resources_locally = base.compile_resources_locally,
|
||||
libtool = base.libtool,
|
||||
momc = base.momc,
|
||||
min_version = base.min_version,
|
||||
xctest = base.xctest,
|
||||
platform_path = base.platform_path,
|
||||
sdk_name = base.sdk_name,
|
||||
sdk_path = base.sdk_path,
|
||||
sdk_version = base.sdk_version,
|
||||
sdk_build_version = base.sdk_build_version,
|
||||
swift_toolchain_info = base.swift_toolchain_info,
|
||||
watch_kit_stub_binary = base.watch_kit_stub_binary,
|
||||
xcode_version = base.xcode_version,
|
||||
xcode_build_version = base.xcode_build_version,
|
||||
),
|
||||
]
|
||||
|
||||
registration_spec = RuleRegistrationSpec(
|
||||
name = "apple_toolchain_override",
|
||||
impl = _impl,
|
||||
attrs = {
|
||||
"base": attrs.dep(providers = [AppleToolchainInfo]),
|
||||
"cxx_toolchain": attrs.dep(providers = [CxxToolchainInfo]),
|
||||
},
|
||||
)
|
||||
36
vendor/cxx/tools/buck/prelude/apple/user/apple_tools.bzl
vendored
Normal file
36
vendor/cxx/tools/buck/prelude/apple/user/apple_tools.bzl
vendored
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load("@prelude//apple:apple_toolchain_types.bzl", "AppleToolsInfo")
|
||||
load("@prelude//user:rule_spec.bzl", "RuleRegistrationSpec")
|
||||
|
||||
def _impl(ctx: "context") -> ["provider"]:
|
||||
return [
|
||||
DefaultInfo(),
|
||||
AppleToolsInfo(
|
||||
assemble_bundle = ctx.attrs.assemble_bundle[RunInfo],
|
||||
info_plist_processor = ctx.attrs.info_plist_processor[RunInfo],
|
||||
make_modulemap = ctx.attrs.make_modulemap[RunInfo],
|
||||
make_vfsoverlay = ctx.attrs.make_vfsoverlay[RunInfo],
|
||||
swift_objc_header_postprocess = ctx.attrs.swift_objc_header_postprocess[RunInfo],
|
||||
),
|
||||
]
|
||||
|
||||
# The `apple_tools` rule exposes a set of supplementary tools
|
||||
# required by the Apple rules _internally_. Such tools are not
|
||||
# toolchain/SDK specific, they're just internal helper tools.
|
||||
registration_spec = RuleRegistrationSpec(
|
||||
name = "apple_tools",
|
||||
impl = _impl,
|
||||
attrs = {
|
||||
"assemble_bundle": attrs.dep(providers = [RunInfo]),
|
||||
"info_plist_processor": attrs.dep(providers = [RunInfo]),
|
||||
"make_modulemap": attrs.dep(providers = [RunInfo]),
|
||||
"make_vfsoverlay": attrs.dep(providers = [RunInfo]),
|
||||
"swift_objc_header_postprocess": attrs.dep(providers = [RunInfo]),
|
||||
},
|
||||
)
|
||||
59
vendor/cxx/tools/buck/prelude/apple/user/apple_watchos_bundle.bzl
vendored
Normal file
59
vendor/cxx/tools/buck/prelude/apple/user/apple_watchos_bundle.bzl
vendored
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load("@prelude//:attributes.bzl", "AppleBundleExtension", "Traversal")
|
||||
load("@prelude//apple:apple_bundle.bzl", "apple_bundle_impl")
|
||||
load("@prelude//apple:apple_rules_impl_utility.bzl", "apple_bundle_extra_attrs")
|
||||
load("@prelude//user:rule_spec.bzl", "RuleRegistrationSpec")
|
||||
load(":watch_transition.bzl", "watch_transition")
|
||||
|
||||
def _apple_bundle_base_attrs():
|
||||
return {
|
||||
# Attributes comes from `attributes.bzl` but since it's autogenerated, we cannot easily abstract
|
||||
"asset_catalogs_compilation_options": attrs.dict(key = attrs.string(), value = attrs.any(), default = {}),
|
||||
"binary": attrs.option(attrs.dep(), default = None),
|
||||
"codesign_flags": attrs.list(attrs.string(), default = []),
|
||||
"codesign_identity": attrs.option(attrs.string(), default = None),
|
||||
"contacts": attrs.list(attrs.string(), default = []),
|
||||
"default_host_platform": attrs.option(attrs.configuration_label(), default = None),
|
||||
"default_platform": attrs.option(attrs.string(), default = None),
|
||||
"deps": attrs.list(attrs.dep(), default = []),
|
||||
"extension": attrs.one_of(attrs.enum(AppleBundleExtension), attrs.string()),
|
||||
"ibtool_flags": attrs.option(attrs.list(attrs.string()), default = None),
|
||||
"ibtool_module_flag": attrs.option(attrs.bool(), default = None),
|
||||
"incremental_bundling_enabled": attrs.option(attrs.bool(), default = None),
|
||||
"info_plist": attrs.source(),
|
||||
"info_plist_substitutions": attrs.dict(key = attrs.string(), value = attrs.string(), sorted = False, default = {}),
|
||||
"labels": attrs.list(attrs.string(), default = []),
|
||||
"licenses": attrs.list(attrs.source(), default = []),
|
||||
"platform_binary": attrs.option(attrs.list(attrs.tuple(attrs.regex(), attrs.dep())), default = None),
|
||||
"product_name": attrs.option(attrs.string(), default = None),
|
||||
"resource_group": attrs.option(attrs.string(), default = None),
|
||||
"resource_group_map": attrs.option(attrs.list(attrs.tuple(attrs.string(), attrs.list(attrs.tuple(attrs.dep(), attrs.enum(Traversal), attrs.option(attrs.string()))))), default = None),
|
||||
"skip_copying_swift_stdlib": attrs.option(attrs.bool(), default = None),
|
||||
"try_skip_code_signing": attrs.option(attrs.bool(), default = None),
|
||||
"within_view": attrs.option(attrs.list(attrs.string())),
|
||||
"xcode_product_type": attrs.option(attrs.string(), default = None),
|
||||
}
|
||||
|
||||
def _apple_watchos_bundle_attrs():
|
||||
attributes = {}
|
||||
attributes.update(_apple_bundle_base_attrs())
|
||||
attributes.update(apple_bundle_extra_attrs())
|
||||
return attributes
|
||||
|
||||
def apple_watchos_bundle_impl(ctx: "context") -> ["provider"]:
|
||||
# This rule is _equivalent_ to `apple_bundle` except it applies
|
||||
# an incoming watchOS transition.
|
||||
return apple_bundle_impl(ctx)
|
||||
|
||||
registration_spec = RuleRegistrationSpec(
|
||||
name = "apple_watchos_bundle",
|
||||
impl = apple_watchos_bundle_impl,
|
||||
attrs = _apple_watchos_bundle_attrs(),
|
||||
cfg = watch_transition,
|
||||
)
|
||||
51
vendor/cxx/tools/buck/prelude/apple/user/resource_group_map.bzl
vendored
Normal file
51
vendor/cxx/tools/buck/prelude/apple/user/resource_group_map.bzl
vendored
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load("@prelude//:attributes.bzl", "Traversal")
|
||||
load(
|
||||
"@prelude//apple:resource_groups.bzl",
|
||||
"ResourceGroupInfo",
|
||||
"create_resource_graph",
|
||||
"get_resource_graph_node_map_func",
|
||||
)
|
||||
load(
|
||||
"@prelude//cxx:groups.bzl",
|
||||
"compute_mappings",
|
||||
"parse_groups_definitions",
|
||||
)
|
||||
load("@prelude//user:rule_spec.bzl", "RuleRegistrationSpec")
|
||||
|
||||
def v1_attrs():
|
||||
return attrs.list(attrs.tuple(attrs.string(), attrs.list(attrs.tuple(attrs.dep(), attrs.enum(Traversal), attrs.option(attrs.string())))))
|
||||
|
||||
def resource_group_map_attr():
|
||||
v2_attrs = attrs.dep(providers = [ResourceGroupInfo])
|
||||
return attrs.option(attrs.one_of(v2_attrs, v1_attrs()), default = None)
|
||||
|
||||
def _impl(ctx: "context") -> ["provider"]:
|
||||
resource_groups = parse_groups_definitions(ctx.attrs.map)
|
||||
resource_groups_deps = [mapping.root.node for group in resource_groups for mapping in group.mappings]
|
||||
resource_graph = create_resource_graph(
|
||||
ctx = ctx,
|
||||
labels = [],
|
||||
deps = resource_groups_deps,
|
||||
exported_deps = [],
|
||||
)
|
||||
resource_graph_node_map = get_resource_graph_node_map_func(resource_graph)()
|
||||
mappings = compute_mappings(groups = resource_groups, graph_map = resource_graph_node_map)
|
||||
return [
|
||||
DefaultInfo(),
|
||||
ResourceGroupInfo(groups = resource_groups, groups_hash = hash(str(resource_groups)), mappings = mappings),
|
||||
]
|
||||
|
||||
registration_spec = RuleRegistrationSpec(
|
||||
name = "resource_group_map",
|
||||
impl = _impl,
|
||||
attrs = {
|
||||
"map": v1_attrs(),
|
||||
},
|
||||
)
|
||||
84
vendor/cxx/tools/buck/prelude/apple/user/watch_transition.bzl
vendored
Normal file
84
vendor/cxx/tools/buck/prelude/apple/user/watch_transition.bzl
vendored
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
"""
|
||||
Transition from iOS to watchOS. Used for watchOS bundle rule.
|
||||
Transforms both OS and SDK constraints.
|
||||
Only sanity check for source configuration is done.
|
||||
"""
|
||||
|
||||
load("@prelude//utils:utils.bzl", "expect")
|
||||
|
||||
def _os_and_sdk_unrelated_constraints(platform: PlatformInfo.type, refs: struct.type) -> {"target_label": ConstraintValueInfo.type}:
|
||||
return {
|
||||
constraint_setting_label: constraint_setting_value
|
||||
for (constraint_setting_label, constraint_setting_value) in platform.configuration.constraints.items()
|
||||
if constraint_setting_label not in [refs.os[ConstraintSettingInfo].label, refs.sdk[ConstraintSettingInfo].label]
|
||||
}
|
||||
|
||||
def _old_os_constraint_value(platform: PlatformInfo.type, refs: struct.type) -> [None, ConstraintValueInfo.type]:
|
||||
return platform.configuration.constraints.get(refs.os[ConstraintSettingInfo].label)
|
||||
|
||||
def _old_sdk_constraint_value(platform: PlatformInfo.type, refs: struct.type) -> [None, ConstraintValueInfo.type]:
|
||||
return platform.configuration.constraints.get(refs.sdk[ConstraintSettingInfo].label)
|
||||
|
||||
def _impl(platform: PlatformInfo.type, refs: struct.type) -> "PlatformInfo":
|
||||
# This functions operates in the following way:
|
||||
# - Start with all the constraints from the platform and filter out the constraints for OS and SDK.
|
||||
# - If the old OS constraint was iOS or watchOS, set the new constraint to be always watchOS.
|
||||
# - If the old SDK constraint was iOS, replace with the equivalent watchOS constraint.
|
||||
# - Return a new platform with the updated constraints.
|
||||
updated_constraints = _os_and_sdk_unrelated_constraints(platform, refs)
|
||||
|
||||
# Update OS constraint
|
||||
old_os = _old_os_constraint_value(platform, refs)
|
||||
watchos = refs.watchos[ConstraintValueInfo]
|
||||
ios = refs.ios[ConstraintValueInfo]
|
||||
if old_os != None:
|
||||
expect(old_os.label in [watchos.label, ios.label], "If present, OS transitioned non-identically to watchOS should be `iphoneos`, got {}".format(old_os.label))
|
||||
updated_constraints[refs.os[ConstraintSettingInfo].label] = watchos
|
||||
|
||||
# Update SDK constraint
|
||||
old_sdk = _old_sdk_constraint_value(platform, refs)
|
||||
watchos_device_sdk = refs.watchos_device_sdk[ConstraintValueInfo]
|
||||
watchos_simulator_sdk = refs.watchos_simulator_sdk[ConstraintValueInfo]
|
||||
ios_device_sdk = refs.ios_device_sdk[ConstraintValueInfo]
|
||||
ios_simulator_sdk = refs.ios_simulator_sdk[ConstraintValueInfo]
|
||||
is_simulator = True
|
||||
if old_sdk != None:
|
||||
if old_sdk.label == watchos_simulator_sdk.label:
|
||||
pass
|
||||
elif old_sdk.label == watchos_device_sdk.label:
|
||||
is_simulator = False
|
||||
elif old_sdk.label == ios_simulator_sdk.label:
|
||||
pass
|
||||
elif old_sdk.label == ios_device_sdk.label:
|
||||
is_simulator = False
|
||||
else:
|
||||
fail("If present, SDK transitioned non-identically to watchOS should be either `iphoneos` or `iphonesimulator`, got {}".format(old_sdk.label))
|
||||
updated_constraints[refs.sdk[ConstraintSettingInfo].label] = watchos_simulator_sdk if is_simulator else watchos_device_sdk
|
||||
|
||||
new_cfg = ConfigurationInfo(
|
||||
constraints = updated_constraints,
|
||||
values = platform.configuration.values,
|
||||
)
|
||||
return PlatformInfo(
|
||||
label = "watch_transition",
|
||||
configuration = new_cfg,
|
||||
)
|
||||
|
||||
# FIXME: prelude// should be standalone (not refer to ovr_config//)
|
||||
watch_transition = transition(impl = _impl, refs = {
|
||||
"ios": "ovr_config//os/constraints:iphoneos",
|
||||
"ios_device_sdk": "ovr_config//os/sdk/apple/constraints:iphoneos",
|
||||
"ios_simulator_sdk": "ovr_config//os/sdk/apple/constraints:iphonesimulator",
|
||||
"os": "ovr_config//os/constraints:os",
|
||||
"sdk": "ovr_config//os/sdk/apple/constraints:_",
|
||||
"watchos": "ovr_config//os/constraints:watchos",
|
||||
"watchos_device_sdk": "ovr_config//os/sdk/apple/constraints:watchos",
|
||||
"watchos_simulator_sdk": "ovr_config//os/sdk/apple/constraints:watchsimulator",
|
||||
})
|
||||
62
vendor/cxx/tools/buck/prelude/apple/xcode.bzl
vendored
Normal file
62
vendor/cxx/tools/buck/prelude/apple/xcode.bzl
vendored
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load("@prelude//apple:apple_sdk.bzl", "get_apple_sdk_name")
|
||||
load("@prelude//apple:apple_target_sdk_version.bzl", "get_min_deployment_version_for_node")
|
||||
load("@prelude//apple:apple_utility.bzl", "has_apple_toolchain")
|
||||
load(
|
||||
"@prelude//cxx:compile.bzl",
|
||||
"CxxSrcWithFlags", # @unused Used as a type
|
||||
)
|
||||
load("@prelude//cxx:xcode.bzl", "cxx_populate_xcode_attributes")
|
||||
load("@prelude//utils:utils.bzl", "expect")
|
||||
|
||||
def apple_populate_xcode_attributes(
|
||||
ctx,
|
||||
srcs: [CxxSrcWithFlags.type],
|
||||
argsfiles_by_ext: {str.type: "artifact"},
|
||||
product_name: str.type) -> {str.type: ""}:
|
||||
data = cxx_populate_xcode_attributes(ctx = ctx, srcs = srcs, argsfiles_by_ext = argsfiles_by_ext, product_name = product_name)
|
||||
|
||||
if has_apple_toolchain(ctx):
|
||||
data["sdk"] = get_apple_sdk_name(ctx)
|
||||
data["deployment_version"] = get_min_deployment_version_for_node(ctx)
|
||||
|
||||
if hasattr(ctx.attrs, "swift_version"):
|
||||
swift_version = ctx.attrs.swift_version
|
||||
if swift_version != None:
|
||||
data["swift_version"] = swift_version
|
||||
|
||||
apple_xcode_data_add_xctoolchain(ctx, data)
|
||||
return data
|
||||
|
||||
def apple_xcode_data_add_xctoolchain(ctx: "context", data: {str.type: ""}):
|
||||
_add_label_for_attr(ctx, "_apple_xctoolchain_bundle_id", "xctoolchain_bundle_id_target", data)
|
||||
_add_output_for_attr(ctx, "_apple_xctoolchain_bundle_id", "xctoolchain_bundle_id", data)
|
||||
_add_label_for_attr(ctx, "_apple_xctoolchain", "xctoolchain_bundle_target", data)
|
||||
|
||||
def _add_label_for_attr(ctx: "context", attr_name: str.type, field_name: str.type, data: {str.type: ""}):
|
||||
xctoolchain_dep = _get_attribute_with_output(ctx, attr_name)
|
||||
if xctoolchain_dep:
|
||||
data[field_name] = xctoolchain_dep.label
|
||||
|
||||
def _add_output_for_attr(ctx: "context", attr_name: str.type, field_name: str.type, data: {str.type: ""}):
|
||||
xctoolchain_dep = _get_attribute_with_output(ctx, attr_name)
|
||||
if xctoolchain_dep:
|
||||
default_info = xctoolchain_dep[DefaultInfo]
|
||||
expect(len(default_info.default_outputs) == 1, "Expected only one output, got {}", len(default_info.default_outputs))
|
||||
data[field_name] = default_info.default_outputs[0]
|
||||
|
||||
def _get_attribute_with_output(ctx: "context", attr_name: str.type) -> ["dependency", None]:
|
||||
if hasattr(ctx.attrs, attr_name):
|
||||
dep = getattr(ctx.attrs, attr_name)
|
||||
default_info = dep[DefaultInfo]
|
||||
if len(default_info.default_outputs) > 0:
|
||||
# When there's no xctoolchain, there will be an empty `DefaultInfo`.
|
||||
# So, an empty `DefaultInfo` basically signifies that there's no xctoolchain.
|
||||
return dep
|
||||
return None
|
||||
9
vendor/cxx/tools/buck/prelude/apple/xcode_postbuild_script.bzl
vendored
Normal file
9
vendor/cxx/tools/buck/prelude/apple/xcode_postbuild_script.bzl
vendored
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
def xcode_postbuild_script_impl(_ctx: "context") -> ["provider"]:
|
||||
return [DefaultInfo()]
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue