Skip to content

A CocoaPods plugin which mangles the symbols of your dependencies

License

Notifications You must be signed in to change notification settings

intercom/cocoapods-mangle

Folders and files

NameName
Last commit message
Last commit date

Latest commit

53c1bc5 Β· Feb 16, 2024

History

76 Commits
Apr 3, 2023
Feb 16, 2024
Feb 16, 2024
Dec 8, 2017
Apr 3, 2023
Apr 8, 2019
Jan 16, 2024
Feb 16, 2024
Dec 6, 2017
Dec 8, 2017
Aug 29, 2018
Feb 16, 2024

Repository files navigation

Intercom

Apache License CircleCI

cocoapods-mangle

cocoapods-mangle is a CocoaPods plugin which mangles the symbols of your dependencies. Mangling your dependencies' symbols allows more than one copy of a dependency to exist in an app. This is particularly useful for iOS frameworks which do not want to interfere with the host app.

Installation

$ gem install cocoapods-mangle

What is mangling?

Mangling or namespacing your dependencies is a way of ensuring that there are no conflicts between multiple copies of the same dependency in an app. This is most useful when developing third-party frameworks.

For example, if you are developing a framework MyFramework.framework and you include AFNetworking as a dependency, all AFNetworking classes are included in your framework's binary:

➜ nm -gU MyFramework.framework/MyFramework | grep "_OBJC_CLASS_\$.*AF.*"
00000000000000e0 S _OBJC_CLASS_$_PodsDummy_AFNetworking
00000000000013f0 S _OBJC_CLASS_$_AFNetworkReachabilityManager
0000000000001f20 S _OBJC_CLASS_$_AFSecurityPolicy
000000000000a938 S _OBJC_CLASS_$_AFHTTPBodyPart
000000000000a898 S _OBJC_CLASS_$_AFHTTPRequestSerializer
000000000000a9d8 S _OBJC_CLASS_$_AFJSONRequestSerializer
000000000000a910 S _OBJC_CLASS_$_AFMultipartBodyStream
000000000000aa28 S _OBJC_CLASS_$_AFPropertyListRequestSerializer
000000000000a848 S _OBJC_CLASS_$_AFQueryStringPair
000000000000a8c0 S _OBJC_CLASS_$_AFStreamingMultipartFormData
0000000000004870 S _OBJC_CLASS_$_AFCompoundResponseSerializer
00000000000046e0 S _OBJC_CLASS_$_AFHTTPResponseSerializer
0000000000004820 S _OBJC_CLASS_$_AFImageResponseSerializer
0000000000004730 S _OBJC_CLASS_$_AFJSONResponseSerializer
00000000000047d0 S _OBJC_CLASS_$_AFPropertyListResponseSerializer
0000000000004780 S _OBJC_CLASS_$_AFXMLParserResponseSerializer

This means that if an app includes both MyFramework.framework and AFNetworking, the app will fail to build with an error that looks something like:

ld: 16 duplicate symbols for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

However, with mangling enabled through cocoapods-mangle, we can see that the AFNetworking classes are now prefixed with MyFramework_:

➜ nm -gU MyFramework.framework/MyFramework | grep "_OBJC_CLASS_\$.*AF.*"
00000000000000e0 S _OBJC_CLASS_$_MyFramework_PodsDummy_AFNetworking
00000000000013f0 S _OBJC_CLASS_$_MyFramework_AFNetworkReachabilityManager
0000000000001f20 S _OBJC_CLASS_$_MyFramework_AFSecurityPolicy
000000000000a938 S _OBJC_CLASS_$_MyFramework_AFHTTPBodyPart
000000000000a898 S _OBJC_CLASS_$_MyFramework_AFHTTPRequestSerializer
000000000000a9d8 S _OBJC_CLASS_$_MyFramework_AFJSONRequestSerializer
000000000000a910 S _OBJC_CLASS_$_MyFramework_AFMultipartBodyStream
000000000000aa28 S _OBJC_CLASS_$_MyFramework_AFPropertyListRequestSerializer
000000000000a848 S _OBJC_CLASS_$_MyFramework_AFQueryStringPair
000000000000a8c0 S _OBJC_CLASS_$_MyFramework_AFStreamingMultipartFormData
0000000000004870 S _OBJC_CLASS_$_MyFramework_AFCompoundResponseSerializer
00000000000046e0 S _OBJC_CLASS_$_MyFramework_AFHTTPResponseSerializer
0000000000004820 S _OBJC_CLASS_$_MyFramework_AFImageResponseSerializer
0000000000004730 S _OBJC_CLASS_$_MyFramework_AFJSONResponseSerializer
00000000000047d0 S _OBJC_CLASS_$_MyFramework_AFPropertyListResponseSerializer
0000000000004780 S _OBJC_CLASS_$_MyFramework_AFXMLParserResponseSerializer

The app that includes both MyFramework.framework and AFNetworking will now build successfully πŸŽ‰

How it works

As demonstrated above, nm can be used to inspect the symbols such as classes, constants and selectors in a Mach-O binary. When you run pod install, cocoapods-mangle builds your dependencies if they have changed, and parses the output of nm. It places this output in an xcconfig file that looks something like this:

MANGLING_DEFINES = PodsDummy_AFNetworking=MyFramework_PodsDummy_AFNetworking AFNetworkReachabilityManager=MyFramework_AFNetworkReachabilityManager AFSecurityPolicy=MyFramework_AFSecurityPolicy AFHTTPBodyPart=MyFramework_AFHTTPBodyPart AFHTTPRequestSerializer=MyFramework_AFHTTPRequestSerializer AFJSONRequestSerializer=MyFramework_AFJSONRequestSerializer AFMultipartBodyStream=MyFramework_AFMultipartBodyStream AFPropertyListRequestSerializer=MyFramework_AFPropertyListRequestSerializer AFQueryStringPair=MyFramework_AFQueryStringPair AFStreamingMultipartFormData=MyFramework_AFStreamingMultipartFormData AFCompoundResponseSerializer=MyFramework_AFCompoundResponseSerializer AFHTTPResponseSerializer=MyFramework_AFHTTPResponseSerializer AFImageResponseSerializer=MyFramework_AFImageResponseSerializer AFJSONResponseSerializer=MyFramework_AFJSONResponseSerializer AFPropertyListResponseSerializer=MyFramework_AFPropertyListResponseSerializer AFXMLParserResponseSerializer=MyFramework_AFXMLParserResponseSerializer

MANGLED_SPECS_CHECKSUM = 18f61e6e6172fb87ddc7341f3537f30f8c7a3edc

This is included in GCC_PREPROCESSOR_DEFINITIONS of the xcconfig file for every target. All of these symbols will be mangled on subsequent builds.

The symbols that will be mangled are:

  • Objective C classes. e.g. AFNetworkReachabilityManager becomes MyFramework_AFNetworkReachabilityManager.
  • C and Objective C constants. AFNetworkingReachabilityDidChangeNotification becomes MyFramework_AFNetworkingReachabilityDidChangeNotification.
  • Objective C category selectors. The first component of the selector is mangled. e.g. -[NSString xxx_abc:def] becomes -[NSString MyFramework_xxx_abc:def].

The plugin has only been fully tested with Objective C dependencies. There is no reason why this could not also work for Swift.

Usage

cocoapods-mangle can be used by adding it to your Podfile like this:

source 'https://github.com/CocoaPods/Specs.git'

platform :ios, '8.0'
plugin 'cocoapods-mangle'

target :MyTarget do
  # Dependencies here
end

Now, each time you run pod install, cocoapods-mangle updates the xcconfig files for all targets to ensure that all symbols in your dependencies are mangled.

The plugin can be optionally configured with :xcconfig_path, :mangle_prefix or :targets. Here is an example:

plugin 'cocoapods-mangle', targets: ['MyTarget'],
                           mangle_prefix: 'Prefix_'
                           xcconfig_path: 'path/to/mangle.xcconfig'

Caveats

  • cocoapods-mangle will only work for source dependencies. Pre-compiled frameworks cannot be mangled.
  • Currently only supports iOS. It should be very straightforward to extend support to macOS, tvOS or watchOS.
  • Category mangling may cause issues if the dependency does not correctly prefix its category selectors (see http://nshipster.com/namespacing/#method-prefixes).
  • Usage of NSClassFromString(@"MyClass") will not work after mangling has been applied. You will need to use NSClassFromString(@"Prefix_MyClass") for this to work correctly.

Related links

About

A CocoaPods plugin which mangles the symbols of your dependencies

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages