Disclaimer: This post is outdated. Even though SwiftPM changed a lot since this post was written, the underlying idea is the same. So, please take with a pinch of salt.
Package.swift as a manifest file to capture information about the current package like, name of the package, its dependencies, targets, etc.,
Package.swift is written in Swift language, parsing it is not as straight forward as parsing
XML. So, how does SwiftPM binary gets the package information?
Hints to this question lies in
Package.swift of SwiftPM itself. Apart from defining root package and its dependencies, SwiftPM also specifies an explicit dynamic library product of PackageDescription module.
Why SwiftPM requires dynamic library for only this module?
PackageDescription is a special module of SwiftPM for 2 reasons:
- It is the only module that must be imported in every
- It has no dependencies on other modules. It’s a design decision. This module is created to be used independently.
The main objective of this
PackageDescription module is to
- Provide APIs for creating Package.swift
- Transmute the Package.swift from its Swifty form to a more consumable format.
Let’s see it in action.
When swift build is invoked with verbose option, it will list out the following command:
So, the above command:
- Compiles the
- Link it will
- Execute the resulting binary with
-fileno argument takes a file descriptor. We can verify this by passing
1, which is the file descriptor for
Package.swift is dumped as
TOML representation on console !!!
Let’s look at how this is implemented.
All magic happens in
Sources/PackageDescription/Package.swift. It contains the following function:
which does two things:
- Create a function dump that creates TOML representation of current package and write it to given file descriptor
- Attach this function to atexit hook, so that it is executed when the program exits
For the curious reader: Sources/PackageLoading/Manifest+parse.swift is also an interesting source file. It contains parse method that actually invokes swiftc to compile Package.swift and get its TOML representation.
swift build is run,
- It creates a file descriptor for writing to
swiftcin another process to compile the
Package.swiftand run the executable with
initmethod is invoked, attaching
dumpmethod to run
- When the execution is about to end,
TOMLdata will be written to the file descriptor
- SwiftPM parses this
TOMLfile and deletes it, that’s why there is no trace of it