RFC: Deprecating generate-xcodeproj

Hello folks,

In add deprecation warning to 'generate-xcodeproj' by tomerd · Pull Request #3062 · apple/swift-package-manager · GitHub we introduced a warning about the upcoming deprecation of SwiftPM's generate-xcodeproj command. The motivation for the upcoming deprecation is the fact that starting Xcode 11, opening and building packages is directly supported by Xcode and therefore we believe that generate-xcodeproj no longer provides material value.

The PR generated some interesting follow-on discussion on how folks are still using generate-xcodeproj, and this thread is an RFC to track such use cases and see how they can be best addressed.

11 Likes

As someone who has been using clion/app for day to day development sometimes I can confirm that it’s support for package.swift has been mature enough for quite a while now and I’ve not had to revert to using the generated package project for a long while already. It used to require going though the Xcode project but nowadays it’s fine without — at least for server side projects, that is.

+1, sounds good to deprecate it at least from my server side clion user perspective ;)

Given that there are settings that can't be persisted or set at all using Package.swift, it still seems important to be able to generate Xcode projects that can. And given the rather poor UX of packages in Xcode, it seems premature to remove the one way to break out of that UX until it's fixed.

11 Likes

Related topic: How to switch package dependencies in Xcode after deprecation of ‘generate-xcodeproj’?

I used to worry that generate-xcodeproj would be dropped before the native package support was capable of everything I needed, as there were originally a handful of problems. However, all but one have since been solved. I haven’t used generate-xcodeproj in my main workflow for months now and my opinion has reversed. I now find it annoying that users expect a package to be compatible with generate-xcodeproj, since it isn’t capable of everything and ends up restricting the features a package can use. For example, XCTest can be used on iOS from a raw package, but if you generate an Xcode project, it will fail to compile. Conditional dependencies were never possible in a generate project either. (I apologize if either of those facts changed in an update without my noticing.) See this post for the fragile hack I am currently applying to differentiate the two build modes for a number of packages.

The one thing I still occasionally use generate-xcodebuild for is to temporarily create a project I can add a run‐script phase to, so that I can see the errors and warnings of external static analysis tools displayed inline by Xcode. There is no way to attach such a script phase to a package, and no other way I know of to get Xcode to parse the output and highlight the offending lines. If there are only a few issues flagged, locating them manually from the line numbers in the terminal output is tolerable. But when I apply a new tool and there are hundreds of warnings, it is much nicer have them funnelled and tabulated into Xcode’s interface, after which each one takes only a single click to navigate to.

A month or two ago, I realized I was a bit of an idiot for not noticing that an Xcode project doesn’t actually have to correspond to the package at all if its only purpose it is to highlight source files. So I may as well just generate an empty one with only the script instead of going through generate-xcodeproj and adding to the result. I will probably have completely switched over to this long before the next version of Swift comes out, so it isn’t a reason to stall deprecation of generate-xcodeproj. Instead I mention it because it seems like something you shouldn’t have to generate a separate project in order to do. Xcode could maybe detect scripts checked in at .swiftpm/xcode/dev-scripts and provide them as isolated schemes available to easily run? Some sort of feature to that effect would be nice.

1 Like

This is a bit off-topic, but can we please get an option in Xcode to create an executable package?

People getting started with Swift using packages will need an executable package, not a library. CLion support this, but Xcode doesn't.

I filed a radar for this over a year ago, but it didn't get a response.

3 Likes

I’m torn about removing generate-xcodeproj from Swift Package Manager.

It is true that Xcode supports packages natively by opening Package.swift. This was a great addition and I’ve been using this feature almost every day over the last year.

It is also true xcodebuild can run package unit tests on a non-macOS platform (eg. iOS). This I learned not too long ago, and was greatly surprised about it.

Both of these features are not well documented or known by many people. Improving documentation would be helpful, for sure, making generate-xcodeproj less relevant.

Yet still, being able to generate Xcode projects from a package can be very handy in some scenarios. It would be a pity having to depend on third-party scripts or applications to do this.

I would like to vote for keeping the feature around. Unless it became a burden to maintain it, that is.

Maybe I am holding it wrong, but I also often swift generate-xcodeproj for my packages to work in Xcode just on tests or sample code or to debug things without creating another dummy Xcode project whose only purpose in life is to depend on my package master/develop branch.

So unless there is a way for Xcode to straight open my project from a local dir directly via Package.swift file, I am also +1 for keeping generate-xcodeproj around for some more time.

It would be good to quantify these scenarios where it would be useful to keep the Xcode project generation around so gaps can be filled.

I think what you're saying here is that you use project generation to enable you to edit your dependencies or work with multiple packages? You can drag packages into a workspace and SwiftPM will switch out the declared dependencies for your local ones

2 Likes

My bad ignorance, I just realized that you can actually open Package.swift and it will open the Package in Xcode allowing you to work on the tests, samples, etc. so I'm now fine and do not need swift generate-xcodeproj.

I use generate-xcodeproj pretty often. My main project is Gryphon, which is a command-line tool, and developing it in Xcode involves at least three things:

  • Setting the "custom working directory" to be $SRCROOT so I can run it from the folder I'm using (instead of one of Xcode's random temporary build folders with a weird name);
  • Setting about ten arguments in "Arguments passed on launch" that I use often so I can turn them on and off during development;
  • Adding a "Run Script Build Phase" to run swiftlint.

Having to do all this every time I open Xcode to work on something would be pretty cumbersome, to say the least. I think the worst part would be adding the arguments: I never remember all of them, and I forget the way some of them are spelled and the options I'm supposed to give them.

If there's a way to save these settings without generate-xcodeproj then it's OK for me, otherwise it's a big -1.

1 Like

You can create a workspace and drag your package into there. then you have all the settings saved in the workspace file (which you can keep outside the package) and don't need an xcodeproj file.

Doesn't generate-xcodeproj wipe out all the settings every time you run it anyway? Opening the Package.swift directly gives you an Xcode workspace in .swiftpm you can check into Git and keep even when changing dependencies etc.

Build phases and scripts are definitely one of the big missing pieces for XPM and SwiftPM in general

1 Like

Please don't do this. At least until there is a way to pass arguments to Xcode when opening a Swift package.

For example, when working on OpenCombine, I usually open two Xcode windows — one with an Xcode project created with the command swift package generate-xcodeproj -Xswiftc -DOPENCOMBINE_COMPATIBILITY_TEST, and one with the package opened through Package.swift. This lets me run OpenCombine tests against Combine, while working on OpenCombine implementation.

If there was a way to pass the -DOPENCOMBINE_COMPATIBILITY_TEST argument to Xcode when opening Package.swift (or at least specify an .xcconfig file), I wouldn't complain.

1 Like

I realize this is an Xcode problem, but it is related.

Our team is in the process of switching most of our libraries from Xcode projects to SPM. However, as detailed in FB7724987, when a project importing these packages is set to gather code coverage from only some targets in Xcode, code coverage isn't actually gathered from them. It works for the same libraries, when they are imported as Xcode projects... so the only workaround we've come up with so far is to use generate-xcodeproj and then link these projects instead of the packages to get the code coverage.

I'd love for this to be fixed in Xcode, but I've pointed this out already during WWDC and it was said to be a known issue then... and supposedly under active investigation... no change since then.

So until this bug is fixed, I'd appreciate if this command continued to exist.

2 Likes

As described in another topic, you can use $ OPENCOMBINE_COMPATIBILITY_TEST=1 open Package.swift.
Although all packages opened by Xcode at the same time are affected by the environment variable in that way. :cry:

Although all packages opened by Xcode at the same time are affected by the environment variable in that way.

That is exactly what I don't want. I want to open the same package in different configurations in two Xcode windows at the same time.

I know how you feel.
I also think 'generate-xcodeproj' should not be deprecated until Xcode introduces new features handling such situations.


Note:
Swift Package Manager itself also adopts "Package.swift" switching dependencies by environment variables: https://github.com/apple/swift-package-manager/blob/4ab1f7c97dab7ae6aa01a4ce992ca76213a94a32/Package.swift#L296-L312

I used generate-xcodeproj because the "Find in project" allows me to search package dependency code as well. When I open Package.swift directly and use Xcode's native support, I can't use Xcode search to find code across all packages.

When I'm developing my Vapor app, for example, it is very useful to search around the Vapor packages for other uses of an API.

Does anyone have a solution for searching code including the packages? I would be very sad if this went away.

I used generate-xcodeproj because the "Find in project" allows me to search package dependency code as well. When I open Package.swift directly and use Xcode's native support, I can't use Xcode search to find code across all packages.

You can change your search scope to search through all packages in the project. On the Find Navigator press New Scope.. and select location "Project". There is no need to generate xcodeproj for all the Vapor packages.

1 Like