Know swift-driver

Introduction

Hello everyone. My name is freddi. I'm an iOS engineer living in Fukuoka, and occasionally studying the Swift compiler, writing articles about the Swift compiler, and giving a talk.

Today, as an article on 12/15 of Swift Advent Calendar 2020, I will introduce the Swift compiler driver swift-driver released by Apple as OSS, and where is its swift-driver. I will briefly explain how it is used.

Swift compiler and driver

swiftc command

Have you ever compiled your Swift code using the swiftc command on Termal without using Xcode?

For example, if you want to compile a source file written in Swift named hello.swift and make it executable on Terminal etc.

$ swiftc hello.swift

I write it like this. You now have an executable file named hello in the same directory.

We are compiling/building the program using the swiftc command like this. Therefore, you may think that the command (program) itself called swiftc is usually the compiler itself.

For example, with the gcc command for compiling C language, the gcc itself is often regarded as the entire compiler program with the same glue.

However, the commands you are touching, such as swiftc and gcc, are actually programs called ** compiler drivers ** that do not include all compilers. So what exactly is a driver?

What is a driver?

First, I will explain something about ** driver **. The driver here refers to a different driver from the one required for the installation of hardware, etc. [^ driver-source]. Even if you search for a driver, you will probably find more hardware here, so it may be difficult to know the meaning of the person who is the subject of this article.

In a nutshell, a driver program is a program that properly references and calls ** programs as parts **. Now let's dig into this meaning using the gcc command as an example. [^ driver-source]

First of all, did you know that there are several phases involved in making a C source file executable with gcc? If you list them roughly in order,

--Pre-process --Compile --Assemble

It is like that.

In fact, each phase is performed by a different command (program), and not all of them are handled by gcc. To enumerate this as well

--Preprocess-cpp command --Compile-cc (1) command --Assemble-- as command --Link --ld etc.

gcc is just ** calling those programs in phase order based on the user's request, such as ** fine optional arguments **. This is the driver program for what is called her compiler. The same is true for swiftc.

For more information on how the driver works, please see http://nenya.cis.ibaraki.ac.jp/TIPS/compiler.html, which was the source of information when writing this item.

The identity of the swiftc / swift command

Here we will focus a bit on the function of the swiftc / swift command as a driver.

In the previous section, I explained that swiftc is a driver program, not the compiler itself, and what a driver program is. Also, as some of you may know, not only swiftc but also the swift command [^ repl] exists, but this is also a driver.

In fact, in the latest Swift compiler branch, swift and swiftc are about the same command, which are symbolic links [^ sl] for the command named swift-frontend. [^ swiftc-github1] [^ swiftc-github2]

The reason why it is divided into swift / swiftc is that the function as a driver of the Swift compiler (generate an executable form, REPL mode etc ...) depends on the optional arguments given. However, it also depends on what name the swift-frontend symbolic link is called.

If you look at https://github.com/apple/swift/blob/main/lib/Driver/Driver.cpp#L98-L105, you can see what command to call and how the driver works. ..

swift-driver

So far, we have talked about drivers for the Swift compiler, but most of the Swift compilers are developed in C ++, and the drivers are also implemented in C ++.

The Swift compiler driver program implemented in the Swift language is ** swift-driver ** in the title. swift-driver has already been adopted in the implementation of Swift Package Manager [^ spm], and it has been used immediately after its appearance. Why did it appear in the first place?

What is swift-driver?

What is swift-driver in the first place?

swift-driver is an OSS made by Apple, which is a port of the function of swift / swiftc mentioned earlier from the C ++ implementation to Swift as much as possible, and the library for realizing it (SwiftDriver etc.) It consists of. I'll explain why later, but I think the internal library called SwiftDriver is the heart of this OSS.

swift-driver only wraps each phase of compilation in Swift as much as possible, and finally needs information such as standard library to call or link through swift-frontend etc. behind the scenes. Therefore, the existing set of Swift compilers needs to be prepared in advance.

Driver implementation with swift-driver

The Swift language implementation of the swift-frontend behavior is here, and if you follow the README.md, it will work first. If you build as described, a command (program) named swift-driver will be generated, which will behave in the same way as the original swift-frontend.

In the same way as the method mentioned earlier in swift-frontend, you can also create a symbolic link named swift or swiftc and call it to branch functions by the called name. You can also add optional arguments similar to the original one.

Personally, I think this swift-frontend is like so-called sample code, and I think the use of libraries such as SwiftDriver here is important.

Why reimplement the driver in the Swift language

It's hard to find a detailed discussion about the benefits of this driver, but it's pretty helpful: There's a Twitter thread where Javi asked a question on Twitter and an Apple engineer named Doug Gregor answered. In summary,

--This driver has an internal build system for incremental builds that is opaque to the build system outside of Swift Package Manager. --This driver allows the Swift Package Manager to integrate driver build tasks into its own build graph and manage concurrent tasks in a single queue. --This driver enables dynamic scheduling

That is a merit. As you can see, it's a little difficult, so in other words, referring to the Description [^ spm] of the Pull Request when swift-driver was introduced in Swift Package Manager.

--A build-related tool made in the Swift language that allows you to treat the Swift compiler as part of your internal Swift program as much as possible, rather than as an external command process such as swift / swiftc. --Since the calls of each phase can be handled in detail through swift-driver, improvements like the above summary that were previously out of reach can be made (now).

I think that is the simplest explanation.

swift-driver can be treated as a Swift library

As you can see from the previous section and the fact that it is incorporated into the Swift Package Manager implementation, swift-driver can be treated as a Swift library named SwiftDriver. Therefore, it is useful for setting up, building, and managing more advanced builds and compilations when creating build tools related to Swift made in the Swift language.

However, to use it successfully, you may need to know some compiler knowledge, the driver implementation of the Swift compiler itself, and so on. Alternatively, you may want to read the Implementation of swift-frontend movement using swift-driver (SwiftDriver) mentioned earlier to deepen your understanding.

Regarding this implementation, I have previously explained in a study session called Waiwai swiftc, so you may want to read this as well.

A little introduction to SwiftDriver

By the way, it's a waste not to get started with SwiftDriver in the explanation so far, so let's get a little introduction to how to use this library.

Let's take a look at the part where Swift Package Manager uses SwiftDriver. The URL of the focusing code is here. Here are some characteristic ones.

Note that this code was from the time Swift Package Manager was introduced and is now mostly modified. I chose the code at this time because I use SwiftDriver most purely and clearly at this time.

First of all, the first two lines, what the hell is this doing?

var driver = try Driver(args: target.emitCommandLine())
let jobs = try driver.planBuild()

The first line creates an object of type Driver in SwiftDriver. This is the command and optional arguments built by Swift Package Manager that should be passed to swift-frontend to the initializer of Driver. As an easy-to-understand example, you can pass swiftc hello.swift.

The following is try driver.planBuild (), which builds which command or program of the compiler should be called in what order from the information passed to Driver, and then displays that information. Returns an array of type Job.

The Job type represents a compiler task, and you can see what it is by looking at [here](https://github.com/apple/swift-driver/tree/main/Sources/SwiftDriver/Jobs) as a derivative of Job. For example, you can see that the compilation is CompileJob and the link is LinkJob and the other Job with the word Link.

You can find out what kind of Job it is by using a variable called kind. The following is the code from line 207 of Swift Package Manager earlier, but I am trying to perform appropriate processing from the information of each task type by turning the jobs generated earlier with a for statement. (FIXME is attached, but it has disappeared because it has been modified a lot now)

// https://github.com/DougGregor/swift-package-manager/blob/c818cdb7d9cbef9d8bff6e0d96cbce9bd77b6bd7/Sources/Build/ManifestBuilder.swift#L207
for job in jobs {
    // Figure out which tool we are using.
    // FIXME: This feels like a hack.
    var datool: String
    switch job.kind {
    case .compile, .mergeModule, .emitModule, .generatePCH,
        .generatePCM, .interpret, .repl, .printTargetInfo,
        .versionRequest:
        datool = buildParameters.toolchain.swiftCompiler.pathString

    case .autolinkExtract, .generateDSYM, .help, .link, .verifyDebugInfo:
        datool = try resolver.resolve(.path(job.tool))
    }
...

In this way, you can easily handle the tasks of the Swift compiler on your Swift program.

Summary

Today, it was a deep topic rather than a topic such as Swift UI and application development, but how was it?

swift-driver is apparently still a developing OSS, and there are comments likeFIXME:everywhere, so I think there are plenty of opportunities to contribute. If you're curious, take a deeper look at the implementation of the Swift compiler itself and take a contribution challenge.

[^ driver-source]: Click here for information source (https://www.quora.com/What-is-a-driver-for-example-a-compiler-driver) Here is also a driver that means hardware There is a commentary

[^ repl]: As many of you may know, this is mainly used for the purpose of calling the REPL mode (http://blog.andgenie.jp/articles/639).

[^ swiftc-github1]: Building the Swift compiler from https://github.com/apple/swift does not generate the swiftc and swift commands as before. Instead, a command named swift-frontend will be generated as described. https://github.com/apple/swift/pull/28003

[^ swiftc-github2]: You can also check by installing the Toolchain from Trunk Development (main) at https://swift.org/download/#releases. By the way, in his current official release, his Xcode 12. *, there is no swift-frontend command yet.

[^ sl]: For the explanation of symbolic links, http://e-words.jp/w/%E3%82%B7%E3%83%B3%E3%83%9C%E3%83%AA%E3 % 83% 83% E3% 82% AF% E3% 83% AA% E3% 83% B3% E3% 82% AF.html #: ~: text =% E3% 82% B7% E3% 83% B3% E3 % 83% 9C% E3% 83% AA% E3% 83% 83% E3% 82% AF% E3% 83% AA% E3% 83% B3% E3% 82% AF% E3% 81% A8% E3% 81 % AF% E3% 80% 81% E3% 82% AA% E3% 83% 9A% E3% 83% AC% E3% 83% BC% E3% 83% 86% E3% 82% A3% E3% 83% B3 % E3% 82% B0,% E3% 81% A7% E3% 81% 8D% E3% 82% 8B% E3% 82% 88% E3% 81% 86% E3% 81% AB% E3% 81% 99% E3% 82% 8B% E4% BB% 95% E7% B5% 84% E3% 81% BF% E3% 80% 82 This is easy to understand

Recommended Posts

Know swift-driver