Edit stdlib and Foundation at the same time?

I've got a bit of a chicken-and-egg problem that I was hoping someone here might be able to help with.

I'm experimenting with some improvements to DecodingError, which lives in the stdlib. The tests for Codable also live in the stdlib. However, the tests I'm working on rely on JSONDecoder, which lives in Foundation. When I modify DecodingError in the stdlib, and then try to run tests, I get crashes when JSONDecoder tries to construct and throw a DecodingError, which I suspect is because there are two versions of DecodingError in play, leading to different memory layouts and other weirdness.

How can I develop changes to Foundation and the stdlib in concert? I have everything checked out, so I can make the changes I want. I can build the toolchain with my stdlib changes, and use that toolchain in Xcode to edit Foundation. But how can I tell my build of the stdlib to use the updated version of Foundation so it gets the right version of JSONDecoder? Will it use my checked-out version of Foundation if I do a full build of the compiler? Or is there anything special I have to do? This question may answer itself, but I'm posting here in case I get an answer before my build finishes :lolsob:

Note: I understand that part of the complexity here is that I'm making changes to the public interface of DecodingError, and that such a change would ultimately require an evolution pitch and approval. Right now, I'm just trying things out, and hopefully I'll find that I don't need to change the public interface at all, but I want to see what's possible.

What platform are you building on/for?

If you build a full toolchain via the build script then it will also build Foundation (first swift-foundation and its dependencies and then swift-corelibs-foundation on top of it). However, on Apple platforms like macOS, the stdlib/Foundation always come from the OS itself (IIRC building a toolchain and selecting it in Xcode to use when building the swift-foundation package will not use the stdlib from that toolchain, it will use the stdlib from your Xcode SDK, and building a macOS toolchain does not build Foundation). So the easiest way to go about building/testing both of these together might be to build via the build script (which will build and test both) on a platform like Linux or Windows instead of macOS (where the build script does not build Foundation because Foundation comes from the OS rather than the toolchain).

Wait, I'm really confused.

If someone wants to work on Foundation, which is mostly used on Apple's platforms, the recommendation is to do so on any platform except Apple's?

4 Likes

There are quite a few ways to build Foundation - those ways are laid out in our document at swift-foundation/Foundation_Build_Process.md at main · swiftlang/swift-foundation · GitHub. This question was specifically about building both the standard library and Foundation together. For developers wishing to just build Foundation, you can easily do so on any applicable platform, Apple platforms included (via SwiftPM, swift-foundation can be built on macOS/Linux/Windows/etc. and swift-corelibs-foundation can be built on Linux/Windows/etc. but not macOS because it is not used on Apple platforms as it does not share source code with Foundation.framework on apple platforms unlike swift-foundation).

However, for building both the stdlib and Foundation together on Apple platforms, this requires building and running Foundation with a stdlib not provided by the OS itself. There are likely ways that you can do this, but to my knowledge Xcode does not support this (at least not with the Toolchains menu bar item selecting an OSS toolchain). So the easiest way is likely to just build the toolchain (which will inherently include Foundation) on Linux (which is easy to do in a container on macOS) which will do everything you need. Other folks on the stdlib side might be able to help explain how you can override which stdlib to use at build and runtime when building another swift package like Foundation if there's a good way to do that.

Thanks for explaining. I'd definitely be interested in hearing if there's a way to do it on macOS, but I'm also getting a VM set up for Linux. Do you have a recommended or preferred setup for that?

Also, just to check my understanding: I don't need to use Xcode to actually run the build and tests; I'm happy to use a CLI invocation for that. But if I'm reading correctly, it sounds like there's no (known/obvious) way to run the stdlib tests on macOS such that changes I've made to JSONDecoder in swift-foundation will be incorporated, because the stdlib always uses the Foundation vended by macOS. Right?

I spoke with @glessard and I think you might want to tweak your approach just a bit. There are stdlib tests that use Foundation, but these are solely to test ObjC bridging support and therefore can only run on Apple platforms and can only run against the OS provided Foundation (as there is no Foundation in the toolchain on macOS). If you're writing a generic (cross platform) unit test that uses JSONDecoder, I think the best place for that is in swift-foundation rather than the stdlib unit tests. That way it'll always use the "just built" foundation when testing.

@glessard also mentioned that there should be a way to use a toolchain (built locally or via swift-ci) in Xcode to build the swift-foundation package against the stdlib from your just-built toolchain so I may have been wrong about the stdlib always coming from the OS. You can try that out to see if it works for you. But I think the reverse (using a just-built Foundation from the stdlib) is a non-goal.

I'm writing tests for DecodingError. The fact that it uses JSONDecoder is just an implementation detail, but it's also status-quo for the existing tests in CodableTests.swift. What I think I'm getting from this is that I should avoid using JSONDecoder for the tests I'm writing, and instead focus on constructing specific DecodingError instances and then testing that they behave as expected. If I want to test how JSONDecoder is producing instances of DecodingError, that is a separate testing concern for Foundation.

2 Likes