Skip to main content
Glama
apple_frameworks.bzl8.75 kB
# 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/swift:swift_compilation.bzl", "extract_swiftmodule_linkables", "get_swiftmodule_linker_flags") load( "@prelude//linking:link_info.bzl", "FrameworksLinkable", "LinkArgs", "LinkInfo", "LinkStrategy", # @unused Used as a type "MergedLinkInfo", "SwiftmoduleLinkable", # @unused Used as a type "get_link_args_for_strategy", "merge_framework_linkables", "merge_swiftmodule_linkables", ) load("@prelude//utils:expect.bzl", "expect") load(":apple_framework_versions.bzl", "get_framework_linker_args", "validate_sdk_frameworks") load(":apple_toolchain_types.bzl", "AppleToolchainInfo") _IMPLICIT_SDKROOT_FRAMEWORK_SEARCH_PATHS = [ "$SDKROOT/Library/Frameworks", "$SDKROOT/System/Library/Frameworks", "$SDKROOT/System/Library/PrivateFrameworks", ] def apple_create_frameworks_linkable(ctx: AnalysisContext) -> [FrameworksLinkable, 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: AnalysisContext, linkable: [FrameworksLinkable, 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: AnalysisContext) -> cmd_args: validate_sdk_frameworks(ctx.attrs.frameworks) 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: list[cmd_args]) -> cmd_args: flags = cmd_args() for directory in frameworks: flags.add(cmd_args(directory, format = "-F{}")) return flags def _get_non_sdk_unresolved_framework_directories(frameworks: list[typing.Any]) -> list[typing.Any]: # 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) -> str: 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) -> str: if ":" in library: fail("Invalid library: {}. Use the field 'linker_flags' with $(location ) macro if you want to pass in a BUCK target for libraries.".format(library)) 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: AnalysisContext, unresolved_framework_paths: list[str]) -> list[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: AnalysisContext, framework_path: str) -> 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) -> [str, 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 apple_build_link_args_with_deduped_flags( ctx: AnalysisContext, deps_merged_link_infos: list[MergedLinkInfo], frameworks_linkable: [FrameworksLinkable, None], link_strategy: LinkStrategy, swiftmodule_linkable: [SwiftmoduleLinkable, None] = None, prefer_stripped: bool = False) -> LinkArgs: frameworks_linkables = [x.frameworks[link_strategy] for x in deps_merged_link_infos] + [frameworks_linkable] swiftmodule_linkables = [x.swiftmodules[link_strategy] for x in deps_merged_link_infos] + [swiftmodule_linkable] link_info = _apple_link_info_from_linkables( ctx, frameworks_linkables, swiftmodule_linkables, ) return get_link_args_for_strategy( ctx, deps_merged_link_infos, link_strategy, prefer_stripped, additional_link_info = link_info, ) def apple_get_link_info_by_deduping_link_infos( ctx: AnalysisContext, infos: list[[LinkInfo, None]], framework_linkable: [FrameworksLinkable, None] = None, swiftmodule_linkable: [SwiftmoduleLinkable, None] = None) -> [LinkInfo, 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) swiftmodule_linkables = extract_swiftmodule_linkables(infos) swiftmodule_linkables.append(swiftmodule_linkable) return _apple_link_info_from_linkables(ctx, framework_linkables, swiftmodule_linkables) def _extract_framework_linkables(link_infos: [list[LinkInfo], None]) -> list[FrameworksLinkable]: linkables = [] for merged in link_infos: for linkable in merged.linkables: if isinstance(linkable, FrameworksLinkable): linkables.append(linkable) return linkables def _apple_link_info_from_linkables( ctx: AnalysisContext, framework_linkables: list[[FrameworksLinkable, None]], swiftmodule_linkables: list[[SwiftmoduleLinkable, None]] = []) -> [LinkInfo, None]: """ Returns a LinkInfo for the frameworks, swiftmodules, and swiftruntimes or None if there's none of those. """ framework_link_args = _get_apple_frameworks_linker_flags(ctx, merge_framework_linkables(framework_linkables)) sdk_swift_module_link_args = get_swiftmodule_linker_flags(ctx, merge_swiftmodule_linkables(ctx, swiftmodule_linkables)) return LinkInfo( pre_flags = [framework_link_args, sdk_swift_module_link_args], ) if (framework_link_args or sdk_swift_module_link_args) else None

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/systeminit/si'

If you have feedback or need assistance with the MCP directory API, please join our Discord server