DylibForge converts static Apple ar archives into dynamic Mach-O libraries. Its dylib-forge command has two subcommands built on the same relinking engine:
xc(orxcframework) converts a complete XCFramework.ar(orarchive) converts one archive or one static framework binary.
Download the latest binaries from GitHub Releases.
DylibForge mechanically transforms supplied binary artifacts for relinking and, for XCFramework inputs, repackaging. It parses binary formats and linker metadata only as required for those transformations. It does not decompile binaries, reconstruct source code, or attempt to infer, evaluate, or model a program's logic, behavior, purpose, or functionality.
Use dylib-forge xc to convert a complete XCFramework. The output path may be the same as the input path.
dylib-forge xc ./Library.xcframework \
--output ./LibraryDynamic.xcframework| Argument | Required | Meaning |
|---|---|---|
<input> |
Yes | Source .xcframework path. |
--output <path> |
Yes | Converted .xcframework path. |
--xcode-path <path> |
No | Xcode .app bundle to use. Defaults to xcode-select. |
--linker-arg-sdk <sdk-or-arg> |
No | SDK name or any followed by raw linker arguments. |
--ignore-autolink-sdk <sdk-or-name> |
No | SDK name or any followed by autolink dependency names to ignore. |
--exclude-object-sdk <sdk-or-pattern> |
No | SDK name or any followed by archive object name patterns to exclude. |
--xcframework-dependency <path> |
No | Dependency .xcframework path. Its matching platform, variant, and architecture slice is linked. |
The command handles every supported static artifact in the XCFramework:
- Converts a
.aarchive into a.dyliband rebuilds a static framework executable in place. - Derives the SDK and install name from the XCFramework metadata and updates the root
Info.plist. - Preserves all other package data, including headers, modules, debug symbols, and dynamic artifacts.
- Removes code signatures and does not sign the result.
Mac Catalyst artifacts are not supported. They are omitted from the output XCFramework and its root
Info.plist. The command logs a warning.
Use SDK-specific controls when linker arguments, ignored autolink dependencies, or excluded archive objects differ between SDKs:
- Start each group with an SDK name or
any. - DylibForge applies every following value to slices built with that SDK until it encounters another SDK name.
- Values in an
anygroup apply to every slice, and values from a specific SDK group are added only to that SDK's slices.
dylib-forge xc ./Library.xcframework --output ./LibraryDynamic.xcframework \
--linker-arg-sdk any \
--linker-arg-sdk -lc++ \
--linker-arg-sdk iphoneos \
--linker-arg-sdk -framework \
--linker-arg-sdk CoreMedia \
--linker-arg-sdk iphonesimulator \
--linker-arg-sdk -Wl,-weak_framework,ARKitThis links -lc++ for every slice, CoreMedia only for iOS-device slices, and weakly links ARKit only for Simulator slices.
Use --xcframework-dependency when the dependency is itself an XCFramework. DylibForge finds the slice with the same platform, variant, and architecture as the library currently being rebuilt, then adds its framework search path and framework name to the linker invocation.
dylib-forge xc ./Library.xcframework \
--output ./LibraryDynamic.xcframework \
--xcframework-dependency ./Dependency.xcframeworkThe same dependency can also be specified explicitly with --linker-arg-sdk:
dylib-forge xc ./Library.xcframework --output ./LibraryDynamic.xcframework \
--linker-arg-sdk iphoneos \
--linker-arg-sdk -F \
--linker-arg-sdk ./Dependency.xcframework/ios-arm64 \
--linker-arg-sdk -framework \
--linker-arg-sdk Dependency \
--linker-arg-sdk iphonesimulator \
--linker-arg-sdk -F \
--linker-arg-sdk ./Dependency.xcframework/ios-arm64_x86_64-simulator \
--linker-arg-sdk -framework \
--linker-arg-sdk DependencyUse dylib-forge ar to convert one standalone archive or framework executable. The output path may be the same as the input path.
dylib-forge ar ./Library.framework/Library \
--output ./Library.framework/Library \
--sdk iphoneos \
--install-name @rpath/Library.framework/Library \
--linker-arg -framework --linker-arg UIKit \
--ignore-autolink PrivateShim \
--exclude-object LegacySimulatorOnly| Argument | Required | Meaning |
|---|---|---|
<input> |
Yes | Path to a static .a archive or to the executable inside a static framework. |
--output <path> |
Yes | Where to write the dynamic binary. |
--sdk <sdk> |
Yes | SDK used for linking, such as iphoneos, iphonesimulator, watchos, or watchsimulator. |
--install-name <name> |
Yes | Value written to LC_ID_DYLIB, for example @rpath/Foo.framework/Foo. |
--xcode-path <path> |
No | Xcode .app bundle to use. Defaults to xcode-select. |
--linker-arg <arg> |
No | Additional raw argument passed to clang while linking. |
--ignore-autolink <name> |
No | Auto-detected autolink dependency name to ignore. |
--exclude-object <pattern> |
No | Object file name substring to skip while unpacking the archive. |
The command:
- Unpacks the
ararchive into Mach-O object files and patches Objective-C symbol visibility. - Drops byte-identical object files and localizes overlapping native symbol definitions.
- Links the remaining objects into a dynamic binary at
--outputusing the supplied SDK and install name.
When the input is a framework executable, this command only converts that executable. It does not copy the framework directory, update a parent XCFramework manifest, remove signatures, or sign the result.
You can either defer undefined symbols to the app that loads the dylib, or link each dependency explicitly.
For a quick attempt at unresolved symbols, pass -Wl,-undefined,dynamic_lookup through a --linker-arg-sdk any group:
dylib-forge xc ./Library.xcframework \
--output ./LibraryDynamic.xcframework \
--linker-arg-sdk any \
--linker-arg-sdk -Wl,-undefined,dynamic_lookupThis asks the final app to resolve undefined symbols at load time. Apple deprecates dynamic_lookup, so explicit linking is preferable when practical.
Instead of -Wl,-undefined,dynamic_lookup, pass the frameworks and libraries that the dynamic binary should link.
dylib-forge xc ./Library.xcframework \
--output ./LibraryDynamic.xcframework \
--linker-arg-sdk any \
--linker-arg-sdk -framework \
--linker-arg-sdk Foundation \
--linker-arg-sdk -lc++ \
--linker-arg-sdk -F"Framework/Search/Path" \
--linker-arg-sdk -Wl,-U,_some_undefined_symbol \
--ignore-autolink-sdk any \
--ignore-autolink-sdk PrivateShim \
--exclude-object-sdk any \
--exclude-object-sdk LegacySimulatorOnlyBoth subcommands handle input archives and framework binaries that contain several architecture slices. Before relinking a static slice, DylibForge asks the selected Xcode whether its SDK and toolchain support that target.
Pass
--xcode-path /Applications/Xcode.appto select Xcode for that command only. Otherwise the Xcode selected byxcode-selectis used. If it does not support a target, the tool logs a warning and continues with the remaining supported architectures.
If an architecture is skipped during dylib-forge xc, the output root Info.plist is updated. Its AvailableLibraries entry receives the actual SupportedArchitectures, and a converted archive receives its new .dylib LibraryPath. The library identifier and directory stay the same, so every manifest path continues to resolve.
The dylib-forge-tests executable builds device and Simulator framework fixtures for macOS, iOS, and watchOS, converts every XCFramework with DylibForge, then runs one shared Swift validation on macOS, iOS Simulator, and watchOS Simulator:
mise install; swift run dylib-forge-tests acceptanceThe idea for this project came from these materials:
- English article: Convert Static Framework to Dynamic
- Russian talk: How Far Would You Go for Working Breakpoints, Vladimir Ozerov
DylibForge is licensed under the MIT License and was originally developed for research purposes. It is provided as-is.
You are responsible for ensuring that you have the right to process, redistribute, ship, or otherwise use any third-party binaries with this tool, including compliance with vendor licenses, Apple platform rules, and applicable legal requirements.
This README is not legal advice.