apple_library

Swift, Objective-C, C, and C++ static library.

Description#

Routes each source file through the driver that matches its extension and emits a .a archive together with the Swift module triple, ObjC interop header, and (optionally) a clang modulemap and binary header map. Multi-arch targets fan out per-arch compiles and merge them with lipo.

Attributes#

AttributeTypeRequiredDefaultDescription
platformstringyesApple platform such as ios, macos, tvos, watchos, or visionos
minimum_osstringnoMinimum supported OS version (deployment target)
target_sdk_versionstringnominimum_osBuild-time SDK version baked into the triple
sdk_variantstringno"simulator"simulator or device. Ignored on macOS (always macosx)
archslist<string>no[]Target architectures (arm64, x86_64, arm64e, arm64_32). Empty defaults to the host arch; multi-arch fans out per-arch compiles and combines them with lipo
mac_catalystboolnofalseBuild the iOSMac (Mac Catalyst) variant. Requires platform = macos; rewrites the triple to <arch>-apple-ios<minOS>-macabi
module_namestringnotarget nameCompiled module name (not configurable)
xcode_developer_dirstringnoPin a specific Xcode by overriding DEVELOPER_DIR. Folded into the action cache key
headerslist<string>no[]Public or private C-family headers compiled with this target
exported_headerslist<string>no[]Headers made available to dependent targets
bridging_headerstringnoObjC bridging header that lets Swift sources see ObjC symbols
swift_flagslist<string>no[]Extra Swift compiler flags
clang_flagslist<string>no[]Extra Clang compiler flags
defineslist<string>no[]-D preprocessor / Swift conditional compilation flags, propagated transitively
enable_testingboolnofalseCompile Swift with testability enabled for dependent tests
library_evolutionboolnofalseEmit stable Swift module interfaces for binary compatibility
enable_modulesboolnofalseEmit a module.modulemap and .hmap from exported_headers and pass -fmodules to Clang
emit_dsymboolnofalseEmit DWARF debug info so downstream target kinds can extract a .dSYM bundle
sdk_frameworkslist<string>no[]Apple SDK frameworks linked by name, propagated transitively
weak_sdk_frameworkslist<string>no[]Apple SDK frameworks linked weakly, propagated transitively
sdk_dylibslist<string>no[]Apple SDK dynamic libraries linked by name, propagated transitively
linkoptslist<string>no[]Extra linker flags, propagated transitively
alwayslinkboolnofalseHint to downstream linker target kinds to force-load this archive (-Wl,-force_load)
exported_depslist<string>no[]Target ids from deps whose module interface flows through to consumers' compile path

Dependency Edges#

EdgeAcceptsDescription
depsapple_linkable, apple_resource, apple_swift_plugin, native_linkableLibraries, frameworks, resources, native linkables, or Swift compiler plugins consumed by this library

A dep that exposes a plugin_dylib provider field (see swift_macro) is auto-detected and threaded into the Swift compile as -load-plugin-library <dylib>.

Providers#

The target emits apple_linkable and apple_module.

Capabilities#

CapabilityOutput groups
builddefault, binary, swiftmodule, generated_sources

Compile pipeline#

Each source extension routes to a different driver:

  • Swift sources go through xcrun --sdk <sdk> swiftc -emit-library -static -emit-module. A bridging_header plumbs in via -import-objc-header so Swift can see ObjC symbols.
  • ObjC, C, and C++ sources each become an independent xcrun --sdk <sdk> clang -c action that writes one .o per source. The clang invocation pulls the SDK sysroot from xcrun --show-sdk-path, targets the active triple, and enables ARC for ObjC.
  • Mixed-language libraries combine the Swift-only archive and the per-source clang objects with xcrun libtool -static. Swift-only or clang-only libraries skip the merge.
  • Multi-arch targets repeat the swift + clang + libtool chain per architecture, then run xcrun lipo -create on the per-arch archives to produce the final universal archive. Single-arch targets skip lipo entirely.

Dep swiftmodule directories are forwarded as -I search paths so import statements resolve. With enable_modules = true the impl writes a module.modulemap from exported_headers, threads it into consumers through the provider, and also writes a binary header map (<module_name>.hmap) mapping each exported header's basename and <module_name>/<basename> form to its workspace-relative path. The hmap is passed to clang and swiftc via -I, covering the #include "Foo.h" and #include <Module/Foo.h> lookup styles a modulemap alone does not.

The action cache key composes the resolved toolchain identity (each of swiftc, clang, libtool, and lipo carries its own xcrun-resolved path, version banner, and any DEVELOPER_DIR override), the source content digests, and each dep's action digest. A swap of Xcode, a source edit, or a transitive dep change invalidates exactly the affected cache slots.

Provider record#

apple_library returns a record consumers read through ctx["deps"]. Fields:

FieldTypeMeaning
label_idstringCanonical target id
swiftmodule_dirstringDirectory holding the .swiftmodule, added to -I by consumers
archivestringFinal static archive path
objc_headerstringGenerated -Swift.h ObjC interop header
modulemapstringPath to the emitted module.modulemap, or empty
hmapstringPath to the emitted .hmap, or empty
exported_headerslist<string>Headers this target re-exposes to consumers
exported_header_dirslist<string>Parent directories of the exported headers, added to -I by consumers
alwayslinkboolHint propagated for force-load
transitive_swiftmodule_dirslist<string>Module search paths (gated by exported_deps)
transitive_exported_headerslist<string>Header paths from this and exported deps
transitive_exported_header_dirslist<string>Header search dirs from this and exported deps
transitive_modulemapslist<string>Modulemap paths to feed downstream consumers
transitive_hmapslist<string>Header-map paths to feed downstream consumers
transitive_archiveslist<string>Archive paths for the link line
transitive_alwayslink_archiveslist<string>Subset of archives that should be force-loaded
transitive_sdk_frameworkslist<string>SDK frameworks to link
transitive_weak_sdk_frameworkslist<string>Weakly linked SDK frameworks
transitive_sdk_dylibslist<string>SDK dynamic libraries to link
transitive_linkoptslist<string>Extra linker flags
transitive_defineslist<string>Preprocessor / conditional compilation flags
transitive_link_framework_bundleslist<record>Dynamic framework bundles carried to the next link action
transitive_framework_bundleslist<record>Dynamic framework bundles carried to the final application or test bundle
transitive_frameworkslist<string>Compatibility view of runtime framework paths

Downstream Apple targets use this record to collect the complete compile and link context without inspecting the dependency's target kind. Dynamic framework dependencies continue through static libraries automatically, so a final application or test does not repeat dependencies that it never imports.

Configurable attributes#

Every attribute except module_name, archs, platform, sdk_variant, and mac_catalyst accepts a select value. Configuration tokens for matching come from the target's resolved literal values:

Token groupSourceExample values
Platformplatformios, macos, tvos, watchos, visionos
SDK variantsdk_variantsimulator, device
Architectureeach entry of archsarm64, x86_64, arm64e, arm64_32
Mac Catalystliteral token when mac_catalyst = truemac_catalyst

Branch keys can combine tokens with : (e.g. ios:simulator); when several branches match the longest matching key wins. A default branch is selected when no other branch matches.

toml
[target.attrs]
sdk_frameworks = { select = { ios = ["UIKit"], macos = ["AppKit"] } }

See Choose Values by Configuration for the guided overview.

Outputs#

OutputLocation
Static archive.once/out/<target>/<module_name>.a
Swift module.once/out/<target>/<module_name>.swiftmodule (single arch) or .swiftmodule/<arch>.swiftmodule (universal)
Swift doc.once/out/<target>/<module_name>.swiftdoc or .swiftmodule/<arch>.swiftdoc
ObjC interop header.once/out/<target>/<module_name>-Swift.h
Modulemap.once/out/<target>/module.modulemap (when enable_modules = true)
Header map.once/out/<target>/<module_name>.hmap (when enable_modules = true)
Per-source clang objects.once/out/<target>/<sanitised_source>[-<arch>].o

Example#

toml
[[target]]
name = "AppCore"
kind = "apple_library"
srcs = ["Sources/**/*.swift", "Sources/**/*.m"]
deps = ["./StringifyMacro"]
[target.attrs]
platform = "ios"
minimum_os = "17.0"
archs = ["arm64", "x86_64"]
sdk_frameworks = ["UIKit"]
enable_modules = true
exported_headers = ["include/AppCore.h"]