Skip to content

Commit

Permalink
Initial Commit
Browse files Browse the repository at this point in the history
  • Loading branch information
brycebostwick committed Feb 22, 2024
0 parents commit c716e12
Show file tree
Hide file tree
Showing 13 changed files with 755 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.DS_Store
xcuserdata/
54 changes: 54 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# XcodePluginLoader

Add plugin support back to Xcode 14+!

`XcodePluginLoader` is a lightweight drop-in, replacement for Xcode's built-in plugin system, which was removed in [Xcode 14.0b3](https://github.com/XVimProject/XVim2/issues/398).

It allows for loading the same plugin bundles that worked in older versions of Xcode.

## How it Works

`XcodePluginLoader` needs to be injected into Xcode (more on that below).
Once it's loaded, it aims to emulate the behavior of Xcode's original plugin loading system — searching for plugin bundles,
performing compatibility checks, and loading / initializing plugins.

A much deeper dive is available on [bryce.co](https://bryce.co/xcode-plugin-loader/).

## Installation

1) [Re-Sign Xcode](https://github.com/XVimProject/XVim2/blob/master/SIGNING_Xcode.md) (the same process you already had to in order to use plugins from Xcode 8 - Xcode 13)

(Note: this limits some functionality within Xcode. Consider keeping a signed copy of Xcode around as well. You can alternatively disable SIP at the expense of security)

2. Build or download the latest release of `XcodePluginLoader`
3. Copy `XcodePluginLoader.dylib` into `Xcode.app/Contents`
4. To run once, use `DYLD_INSERT_LIBRARIES=@executable_path/../XcodePluginLoader.dylib /path/to/Xcode.app/Contents/MacOS/Xcode`
5. For a more permanant setup, use [`optool`](https://github.com/alexzielenski/optool) to modify your Xcode binary to inject the plugin loader every time: `optool install -p "@executable_path/../XcodePluginLoader.dylib" -t /path/to/Xcode.app/Contents/MacOS/Xcode`

## Plugin Compatibility

Just like Xcode's original plugin system, this loader checks plugin bundles for compatibility before loading them. Plugins will have to be tested on newer Xcode versions and then updated to indicate that they're compatible.

For Xcode 14.0 - 15.2, plugins can add [`DVTPlugInCompatibilityUUIDs`](https://gist.github.com/minsko/9124ee24b9422fb8ea6b8d00815783ba) to their `Info.plist` files to specify which versions of Xcode they're compatible with.

For Xcode 15.3+, plugins should instead specify `DTXcodeBuildCompatibleVersions` in their `Info.plist` file, based on Xcode's build number (like `15E5194e`). The lowercase letter suffix is optional and should generally be dropped, unless compatibility with specific builds is needed.

These two compatibility values can exist side-by-side:

```xml
<key>DTXcodeBuildCompatibleVersions</key>
<array>
<string>15E5178</string>
<string>15E5188</string>
</array>
<key>DVTPlugInCompatibilityUUIDs</key>
<array>
<string>EFD92DF8-D0A2-4C92-B6E3-9B3CD7E8DC19</string>
<string>8BAA96B4-5225-471B-B124-D32A349B8106</string>
<string>7A3A18B7-4C08-46F0-A96A-AB686D315DF0</string>
</array>
```

## Debugging

When properly loaded into Xcode, `XcodePluginLoader` will log information about what it's doing; either use `Console.app` or launch Xcode via Terminal to see its output.
326 changes: 326 additions & 0 deletions XcodePluginLoader.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,326 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 56;
objects = {

/* Begin PBXBuildFile section */
020463992B7437AF00BF01DB /* XcodePluginLoader.h in Headers */ = {isa = PBXBuildFile; fileRef = 020463982B7437AF00BF01DB /* XcodePluginLoader.h */; };
0204639B2B7437AF00BF01DB /* XcodePluginLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = 0204639A2B7437AF00BF01DB /* XcodePluginLoader.m */; };
020463A42B7534C900BF01DB /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 020463A32B7534C900BF01DB /* main.m */; };
020463A92B7535A000BF01DB /* ClassLoadObserver.h in Headers */ = {isa = PBXBuildFile; fileRef = 020463A72B7535A000BF01DB /* ClassLoadObserver.h */; };
020463AA2B7535A000BF01DB /* ClassLoadObserver.m in Sources */ = {isa = PBXBuildFile; fileRef = 020463A82B7535A000BF01DB /* ClassLoadObserver.m */; };
/* End PBXBuildFile section */

/* Begin PBXFileReference section */
020463952B7437AF00BF01DB /* XcodePluginLoader.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = XcodePluginLoader.dylib; sourceTree = BUILT_PRODUCTS_DIR; };
020463982B7437AF00BF01DB /* XcodePluginLoader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = XcodePluginLoader.h; sourceTree = "<group>"; };
0204639A2B7437AF00BF01DB /* XcodePluginLoader.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = XcodePluginLoader.m; sourceTree = "<group>"; };
020463A32B7534C900BF01DB /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
020463A62B75355700BF01DB /* XcodePlugin.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = XcodePlugin.h; sourceTree = "<group>"; };
020463A72B7535A000BF01DB /* ClassLoadObserver.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ClassLoadObserver.h; sourceTree = "<group>"; };
020463A82B7535A000BF01DB /* ClassLoadObserver.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ClassLoadObserver.m; sourceTree = "<group>"; };
020463AB2B753EF800BF01DB /* DVTPlugInManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DVTPlugInManager.h; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
020463932B7437AF00BF01DB /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */

/* Begin PBXGroup section */
0204638C2B7437AF00BF01DB = {
isa = PBXGroup;
children = (
020463972B7437AF00BF01DB /* XcodePluginLoader */,
020463962B7437AF00BF01DB /* Products */,
);
sourceTree = "<group>";
};
020463962B7437AF00BF01DB /* Products */ = {
isa = PBXGroup;
children = (
020463952B7437AF00BF01DB /* XcodePluginLoader.dylib */,
);
name = Products;
sourceTree = "<group>";
};
020463972B7437AF00BF01DB /* XcodePluginLoader */ = {
isa = PBXGroup;
children = (
0285D3B02B86E26D002A563F /* Helpers */,
020463A52B75354700BF01DB /* XcodeHeaders */,
020463982B7437AF00BF01DB /* XcodePluginLoader.h */,
0204639A2B7437AF00BF01DB /* XcodePluginLoader.m */,
020463A32B7534C900BF01DB /* main.m */,
);
path = XcodePluginLoader;
sourceTree = "<group>";
};
020463A52B75354700BF01DB /* XcodeHeaders */ = {
isa = PBXGroup;
children = (
020463AB2B753EF800BF01DB /* DVTPlugInManager.h */,
020463A62B75355700BF01DB /* XcodePlugin.h */,
);
path = XcodeHeaders;
sourceTree = "<group>";
};
0285D3B02B86E26D002A563F /* Helpers */ = {
isa = PBXGroup;
children = (
020463A72B7535A000BF01DB /* ClassLoadObserver.h */,
020463A82B7535A000BF01DB /* ClassLoadObserver.m */,
);
path = Helpers;
sourceTree = "<group>";
};
/* End PBXGroup section */

/* Begin PBXHeadersBuildPhase section */
020463912B7437AF00BF01DB /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
020463992B7437AF00BF01DB /* XcodePluginLoader.h in Headers */,
020463A92B7535A000BF01DB /* ClassLoadObserver.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXHeadersBuildPhase section */

/* Begin PBXNativeTarget section */
020463942B7437AF00BF01DB /* XcodePluginLoader */ = {
isa = PBXNativeTarget;
buildConfigurationList = 0204639E2B7437AF00BF01DB /* Build configuration list for PBXNativeTarget "XcodePluginLoader" */;
buildPhases = (
020463912B7437AF00BF01DB /* Headers */,
020463922B7437AF00BF01DB /* Sources */,
020463932B7437AF00BF01DB /* Frameworks */,
);
buildRules = (
);
dependencies = (
);
name = XcodePluginLoader;
productName = XcodePluginLoader;
productReference = 020463952B7437AF00BF01DB /* XcodePluginLoader.dylib */;
productType = "com.apple.product-type.library.dynamic";
};
/* End PBXNativeTarget section */

/* Begin PBXProject section */
0204638D2B7437AF00BF01DB /* Project object */ = {
isa = PBXProject;
attributes = {
BuildIndependentTargetsInParallel = 1;
LastUpgradeCheck = 1520;
TargetAttributes = {
020463942B7437AF00BF01DB = {
CreatedOnToolsVersion = 15.2;
};
};
};
buildConfigurationList = 020463902B7437AF00BF01DB /* Build configuration list for PBXProject "XcodePluginLoader" */;
compatibilityVersion = "Xcode 14.0";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 0204638C2B7437AF00BF01DB;
productRefGroup = 020463962B7437AF00BF01DB /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
020463942B7437AF00BF01DB /* XcodePluginLoader */,
);
};
/* End PBXProject section */

/* Begin PBXSourcesBuildPhase section */
020463922B7437AF00BF01DB /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
020463A42B7534C900BF01DB /* main.m in Sources */,
0204639B2B7437AF00BF01DB /* XcodePluginLoader.m in Sources */,
020463AA2B7535A000BF01DB /* ClassLoadObserver.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */

/* Begin XCBuildConfiguration section */
0204639C2B7437AF00BF01DB /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
GCC_C_LANGUAGE_STANDARD = gnu17;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
MACOSX_DEPLOYMENT_TARGET = 14.0;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = macosx;
};
name = Debug;
};
0204639D2B7437AF00BF01DB /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
GCC_C_LANGUAGE_STANDARD = gnu17;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
MACOSX_DEPLOYMENT_TARGET = 14.0;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
SDKROOT = macosx;
};
name = Release;
};
0204639F2B7437AF00BF01DB /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = FGFSR7EX83;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
};
name = Debug;
};
020463A02B7437AF00BF01DB /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = FGFSR7EX83;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
};
name = Release;
};
/* End XCBuildConfiguration section */

/* Begin XCConfigurationList section */
020463902B7437AF00BF01DB /* Build configuration list for PBXProject "XcodePluginLoader" */ = {
isa = XCConfigurationList;
buildConfigurations = (
0204639C2B7437AF00BF01DB /* Debug */,
0204639D2B7437AF00BF01DB /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
0204639E2B7437AF00BF01DB /* Build configuration list for PBXNativeTarget "XcodePluginLoader" */ = {
isa = XCConfigurationList;
buildConfigurations = (
0204639F2B7437AF00BF01DB /* Debug */,
020463A02B7437AF00BF01DB /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 0204638D2B7437AF00BF01DB /* Project object */;
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit c716e12

Please sign in to comment.