From c01ae50a326c3a9b77c7b3d60b8e4c90007640b7 Mon Sep 17 00:00:00 2001 From: Lawrence Lomax Date: Fri, 8 Jul 2016 02:48:43 -0700 Subject: [PATCH] Use Framework Versioning to prevent Runtime Duplicate Symbols Summary: `FBControlCore` has some provisional Framework Version build settings enabled and is the only of the 4 Objective-C Frameworks to do so. `XCTestBootstrap` does not have versioning, but is embedded in both `FBSimulatorControl` and `FBDeviceControl` just like `FBControlCore` is. This poses a problem when `FBSimulatorControl` and `FBDeviceControl` are both loaded into the same process: 1) `fbsimctl` loads `FBSimulatorControl`, `dyld` loads the Frameworks in `FBSimulatorControl.framework/Frameworks` of `FBControlCore` & `XCTestBootstrap`. 2) `fbsimctl` loads `FBDeviceControl`, `dyld` loads the the Frameworks in `FBDeviceControl.framework/Frameworks`. 3) `FBControlCore` is not loaded as it has the same Framework version as was loaded in #1 4) `XCTestBootstrap` is loaded *again* since it has no versioning information 5) `dyld` complains about duplicate symbols at runtime. Adding Versioning to `XCTestBootstrap` has the effect that `dyld` will be smart enough to not complain about duplicate symbols in `XCTestBootstrap`. This means that we can keep `FBSimulatorControl` as being completly (and independently) redistributable as a Framework as it will continue to bundle its dependencies, but also prevent runtime duplicate symbols. Reviewed By: marekcirkos Differential Revision: D3533943 fbshipit-source-id: bf9bc7562a1a4a6275d6d6089bf2da4825c9637e --- Configuration/Framework.xcconfig | 12 ++++++++++++ FBControlCore/FBControlCore.xcconfig | 13 +++---------- FBDeviceControl/FBDeviceControl.xcconfig | 5 ++--- FBSimulatorControl.xcodeproj/project.pbxproj | 2 ++ FBSimulatorControl/FBSimulatorControl.xcconfig | 5 ++--- XCTestBootstrap/XCTestBootstrap.xcconfig | 3 ++- 6 files changed, 23 insertions(+), 17 deletions(-) create mode 100644 Configuration/Framework.xcconfig diff --git a/Configuration/Framework.xcconfig b/Configuration/Framework.xcconfig new file mode 100644 index 00000000..97cda0f0 --- /dev/null +++ b/Configuration/Framework.xcconfig @@ -0,0 +1,12 @@ +// Adding 'Versioning' to the Framework will ensure that Duplicate Symbol Scenarios do not arise when the Frameworks are independently distributed +// Since FBSimulatorControl/FBDeviceControl both embed XCTestBootstrap & FBControlCore, the versioning of these Frameworks will ensure that dyld +// is aware of the embedded Frameworks in these Targets being identical and won't attempt to load them twice. + +CURRENT_PROJECT_VERSION = 1 +DEFINES_MODULE = YES; +DYLIB_COMPATIBILITY_VERSION = 1 +DYLIB_CURRENT_VERSION = 1 +DYLIB_INSTALL_NAME_BASE = @rpath +FRAMEWORK_VERSION = A +VERSIONING_SYSTEM = apple-generic +LD_RUNPATH_SEARCH_PATHS = $(inherited) @executable_path/../Frameworks @loader_path/Frameworks diff --git a/FBControlCore/FBControlCore.xcconfig b/FBControlCore/FBControlCore.xcconfig index 8c18ff8f..22529f7b 100644 --- a/FBControlCore/FBControlCore.xcconfig +++ b/FBControlCore/FBControlCore.xcconfig @@ -1,15 +1,8 @@ -// Import Shared Configuration +// Import Shared & Framework Configuration #include "../Configuration/Shared.xcconfig" +#include "../Configuration/Framework.xcconfig" // Target-Specific Settings -CURRENT_PROJECT_VERSION = 1 -DEFINES_MODULE = YES; -DYLIB_COMPATIBILITY_VERSION = 1 -DYLIB_CURRENT_VERSION = 1 -DYLIB_INSTALL_NAME_BASE = @rpath -FRAMEWORK_VERSION = A INFOPLIST_FILE = $(SRCROOT)/FBControlCore/FBControlCore-Info.plist -LD_RUNPATH_SEARCH_PATHS = $(inherited) @executable_path/../Frameworks @loader_path/Frameworks PRODUCT_BUNDLE_IDENTIFIER = com.facebook.FBControlCore -PRODUCT_NAME = FBControlCore -VERSIONING_SYSTEM = apple-generic \ No newline at end of file +PRODUCT_NAME = FBControlCore \ No newline at end of file diff --git a/FBDeviceControl/FBDeviceControl.xcconfig b/FBDeviceControl/FBDeviceControl.xcconfig index 3f406804..3ef9019f 100644 --- a/FBDeviceControl/FBDeviceControl.xcconfig +++ b/FBDeviceControl/FBDeviceControl.xcconfig @@ -1,12 +1,11 @@ -// Import Shared Configuration +// Import Shared & Framework Configuration #include "../Configuration/Shared.xcconfig" +#include "../Configuration/Framework.xcconfig" // Weak-Link Xcode Private Frameworks OTHER_LDFLAGS = $(inherited) -weak_framework DTXConnectionServices -weak_framework DVTFoundation -weak_framework IBAutolayoutFoundation -weak_framework IDEFoundation -weak_framework IDEKit -weak_library $(DEVELOPER_DIR)/../PlugIns/IDEiOSSupportCore.ideplugin/Contents/MacOS/IDEiOSSupportCore -weak_library $(DEVELOPER_DIR)/../PlugIns/IDESourceEditor.ideplugin/Contents/MacOS/IDESourceEditor // Target-Specific Settings -DEFINES_MODULE = YES; INFOPLIST_FILE = $(SRCROOT)/FBDeviceControl/FBDeviceControl-Info.plist -LD_RUNPATH_SEARCH_PATHS = @loader_path/Frameworks PRODUCT_BUNDLE_IDENTIFIER = com.facebook.FBDeviceControl PRODUCT_NAME = FBDeviceControl \ No newline at end of file diff --git a/FBSimulatorControl.xcodeproj/project.pbxproj b/FBSimulatorControl.xcodeproj/project.pbxproj index df871ab9..225edb09 100644 --- a/FBSimulatorControl.xcodeproj/project.pbxproj +++ b/FBSimulatorControl.xcodeproj/project.pbxproj @@ -777,6 +777,7 @@ AA9B24D71D07F9BB00CEE14F /* FBiOSTargetPredicates.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBiOSTargetPredicates.m; sourceTree = ""; }; AAA46E431C0CB92A009D6452 /* FBSimulatorControl.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = FBSimulatorControl.xcconfig; sourceTree = ""; }; AAA55F641D0088E800BC4824 /* FBControlCoreTests.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = FBControlCoreTests.xcconfig; sourceTree = ""; }; + AAA5DE491D2F8F71008A36ED /* Framework.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Framework.xcconfig; sourceTree = ""; }; AAAA67C41BC4FED200075197 /* FBSimulatorControlFixtures.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBSimulatorControlFixtures.h; sourceTree = ""; }; AAAA67C51BC4FED200075197 /* FBSimulatorControlFixtures.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBSimulatorControlFixtures.m; sourceTree = ""; }; AAAA67C71BC5018500075197 /* TableSearch.app */ = {isa = PBXFileReference; lastKnownFileType = wrapper.application; path = TableSearch.app; sourceTree = ""; }; @@ -1308,6 +1309,7 @@ AA633F8A1CFD788F00A59C5F /* Configuration */ = { isa = PBXGroup; children = ( + AAA5DE491D2F8F71008A36ED /* Framework.xcconfig */, AA633F8B1CFD788F00A59C5F /* Shared.xcconfig */, ); path = Configuration; diff --git a/FBSimulatorControl/FBSimulatorControl.xcconfig b/FBSimulatorControl/FBSimulatorControl.xcconfig index ac66c53e..731ee497 100644 --- a/FBSimulatorControl/FBSimulatorControl.xcconfig +++ b/FBSimulatorControl/FBSimulatorControl.xcconfig @@ -1,12 +1,11 @@ -// Import Shared Configuration +// Import Shared & Framework Configuration #include "../Configuration/Shared.xcconfig" +#include "../Configuration/Framework.xcconfig" // Weak-Link Xcode Private Frameworks OTHER_LDFLAGS = $(inherited) -weak_framework DVTFoundation -weak_framework DVTiPhoneSimulatorRemoteClient -weak_framework CoreSimulator -weak_framework SimulatorKit // Target-Specific Settings -DEFINES_MODULE = YES; INFOPLIST_FILE = $(SRCROOT)/FBSimulatorControl/FBSimulatorControl-Info.plist; -LD_RUNPATH_SEARCH_PATHS = @loader_path/Frameworks PRODUCT_BUNDLE_IDENTIFIER = com.facebook.FBSimulatorControl PRODUCT_NAME = FBSimulatorControl diff --git a/XCTestBootstrap/XCTestBootstrap.xcconfig b/XCTestBootstrap/XCTestBootstrap.xcconfig index 4f1f9050..4037dbbc 100644 --- a/XCTestBootstrap/XCTestBootstrap.xcconfig +++ b/XCTestBootstrap/XCTestBootstrap.xcconfig @@ -1,5 +1,6 @@ -// Import Shared Configuration +// Import Shared & Framework Configuration #include "../Configuration/Shared.xcconfig" +#include "../Configuration/Framework.xcconfig" // Target-Specific Settings DEFINES_MODULE = YES;