xcodexcodebuildswiftlintxcode-build-settings

Reusing build phase for multiple targets in Xcode


Can I reuse the same build phase for multiple targets?

I have multiple targets on my project and I want to run SwiftLint for all the targets as a build phase.

Is there a way I can achieve this without duplicating the build phase?


Solution

  • You can. Although is a bit of a manual endeavor.

    When you create build phases, Xcode creates a unique reference id for the build phase. Xcode has an array for your build phases with names and reference ids. This reference id is used to reference the content of the build phase.

    If you open up your .pbxproj file, you can manually change the reference id's to be the same. The file is found inside your .xcodeproj. Show the project in finder -> Right click on the .xcodeproj file -> Click on Show Package Contents -> Open project.pbxproj file.

    In the project file you can find build phases "array" inside every target. The section will look like something like this:

    buildPhases = (
                    1232BB9B27B275C300A05A1E /* Sources */,
                    1232BB9C27B275C300A05A1E /* Frameworks */,
                    1232BB9D27B275C300A05A1E /* Resources */,
                    346E52AF28EC321F00CB6A61 /* SwiftLint */,
                );
    

    The first item is the reference id, the comment tells the name of the referenced build phase for clarity. Later in the file you can find the actual implementation of the build phases. My SwiftLint phase looks like this:

    /* Begin PBXShellScriptBuildPhase section */
            346E52AF28EC321F00CB6A61 /* SwiftLint */ = {
                isa = PBXShellScriptBuildPhase;
                alwaysOutOfDate = 1;
                buildActionMask = 2147483647;
                files = (
                );
                inputFileListPaths = (
                );
                inputPaths = (
                );
                name = SwiftLint;
                outputFileListPaths = (
                );
                outputPaths = (
                );
                runOnlyForDeploymentPostprocessing = 0;
                shellPath = /bin/sh;
                shellScript = "# This workflow is shared between all targets.\nexport PATH=\"$PATH:$HOME/.mint/bin\"\nif which swiftlint >/dev/null; then\n    swiftlint\nelse\n    echo \"warning: SwiftLint not installed. Follow the instructions located in docs/styleGuide.md.\"\nfi\n";
            };
    /* End PBXShellScriptBuildPhase section */
    

    If you make the build phase multiple times by copy pasting the contents, you will have multiples of the same build phase with different id's.

    So you can delete the duplicate phases and replace the reference id for all the targets with the remaining build phase id. In this case 346E52AF28EC321F00CB6A61.

    Took me a bit to find this out, so hopefully this helps other people searching for the same solution.

    Note: Tested with Xcode 14.0.1