Adding an executable SPM Dependency in Xcode 11?

Hi, I am in the process of writing a build phase script that will parse configuration files and generate Swift wrapper classes to safely access those files at runtime. To get higher adoption and use the latest Xcode 11 features I would very much like to distribute it as an executable Swift Package (under SPM).

Is it currently possible (in Xcode 11), to specify an executable SPM dependency for an iOS project and then run the binary produced by that dependency in a build phase script? I don't want to include or use any code from the package in the app target. I just want to use the executable in a build phase script to generate Swift classes that I will later use in the main iOS project.

1 Like

That sounds like a perfect use case for extensible build tools in the long run.

For the moment though (last I checked anyway) including an executable target interferes with iOS compatibility package‐wide.

The most vanilla solution in the meantime would be to provide a build phase for users to copy and paste. The short script would clone, build, and execute your package as a separate entity (caching it of course). The .swiftpm directory would be a good place to store the cache. This Gist demonstrates a more complete, permanent, system‐wide install of an arbitrary package tool; you could use it as a starting point, but strip out the parts you don’t need.

But for users already familiar with the package manager, all you really have to do is make it obvious that you vend the tool as a Swift package. They will then be able to figure out countless ways of integrating it into their workflow just the way they want. They may use the package manager directly, or they may use some third party tool that further simplifies the process in some way (there are many such tools and scripts out in the wild).

3 Likes

This is possible since executable targets in a package always build for macOS. Add the executable product from the package in the target dependency build phase. Then you should be able to find that executable in the built products directory using the available environment variables.

1 Like

It’d be great if you can file bugs that you’ve seen in this area!

Do you mean with $ swift build, or do you mean when you click the build button in Xcode while the package scheme and an iPhone device are selected?

(This is not something I have tried with Xcode 11 yet. My information could be stale; Xcode 10 just aborts with error: unable to resolve product type 'com.apple.product-type.tool' for platform 'iphoneos' (in target 'MyExecutable').)

I was never sure if it was a bug or not, since the official status of SwiftPM + iOS was unclear. But I’d be happy to officially report it if you consider it to be bug, and if it still occurs with Xcode 11.

Ah, I meant when you build Swift packages using the Swift package support in Xcode 11 (not command-line SwiftPM's generated project support). The error you saw is expected if you try to build executables for non-macOS platforms in Xcode.

I created a sample to demonstrate how to do this in Xcode 11: https://github.com/aciidb0mb3r/swift-package-manager/tree/examples/build-time-dependency

2 Likes

Thanks a lot this is exactly what I was looking for. I appreciate the additional effort of setting up the example project!

One question regarding the example. You are invoking the CodeGenTool with the command:

$SYMROOT/$CONFIGURATION/CodeGenTool

This looks a little magical. Did you first had to build the tool or does it get built by Xcode when building the app target? Also, what does $SYMROOT/$CONFIGURATION resolve to and will it always contain the CodeGenTool executable?

1 Like

What I did to replace something I was previously doing with git-submodules is find a way to get a reference to the package repo from a script build-phase. It's a pretty dirty hack that uses Xcode's organization of packages, so use at your own risk :innocent:

Here's a stripped down version:

#Get the build directory of the project
build_dir=`xcodebuild -project $PROJECT_NAME.xcodeproj -showBuildSettings | grep -m 1 "BUILD_DIR" | grep -oEi "\/.*"`

# This is the path for the checkouts for SPM. Just replace "##PackageName##" with your package name
project_dir=$build_dir/../../SourcePackages/checkouts/##PackageName##

#this is how I'm using it:
buildscript_path=$project_dir/app/buildTool.sh

sh $buildscript_path (...My Parameters...)

Please don’t do this :sob:

1 Like

Didn't say it was a good solution! :smile:

when I (have time to) figure out how to make what I'm doing into an SPM executable I'm planning on switching to your approach, but my way made it easier to adapt existing infrastructure.

1 Like

Hi @Aciid, your example project only seems to work with local dependencies. If I add a remote dependency through a Github repo, Xcode does not show me the executable target hence I cannot build the tool and run it.

Is there a way to use a remote executable dependency as a build phase script?

Terms of Service

Privacy Policy

Cookie Policy