[cmake-developers] Adding Swift support to CMake for Linux/Makefiles

Brad King brad.king at kitware.com
Wed Jan 13 10:07:39 EST 2016

On 01/13/2016 07:00 AM, Eric Wing wrote:
> So I got the trivial base case working with swiftc (no library
> dependencies, Mac for now but will shift to Linux eventually):
> add_exectuable(MyTarget main.swift)


> Problem 1: Intermixing C and Swift
> add_exectuable(MyTarget main.swift some_c.c)
> Note: I presume C++ (and Obj-C) could also be in the mix:
> add_exectuable(MyTarget main.swift some_c.c some_cpp.cpp some_objc.m)
> It looks like the link phase is invoking cc on my system (the C linker
> rules?) instead of the Swift linker commands.
> If my hunch is correct, how do I tell CMake to ‘promote’ Swift as the
> correct tool?

See the CMAKE_<LANG>_LINKER_PREFERENCE platform information variable.
There is also the LINKER_LANGUAGE target property.  For C, C++, and
Fortran one generally chooses between C++ and Fortran to drive the
linker based on which language has the entry point (main) in its
sources.  If we see a "main.swift" then we know Swift should be used.
If not then I don't know enough about Swift linking requirements to say.

> Problem 2: Multiple Swift files in the target
> add_exectuable(MyTarget main.swift OtherSwift.swift)
> With two or more files, I was hoping to do a single one-shot call:
> swiftc -c OtherSwift.swift main.swift -module-name MyTarget
> But before I move on to that, is there a way to get CMake to invoke
> all the Swift files in the target together? (It would need to exclude
> any non-Swift files in the list.)
> I think there may be trade-offs here. On one hand, file-by-file might
> get us incremental compilation. But there is a flag called
> -whole-module-optimization which suggests treating them as a batch
> could allow better code generation.

This looks like a semantic difference between how the switfc and cc
compilers work that as I feared in my previous response may require
C++ changes to CMake to make work.  Before diving into that we need
to understand the preferred way to compile multiple Swift sources.
Last time I looked at this the only reference was "what Xcode does".
Hopefully there is more information out there now.

> Now for the 'swift' tool:
> So the swift tool can go file-by-file, but the additional constraint
> is that all the other Swift files in the target must be listed too. To
> distinguish which file is actually being processed, you must use the
> -primary-file <active_file.swift> <other_files>. I think this is so
> Swift can figure out all the cross-file dependencies since there are
> no header files in Swift.

Interesting.  My previous comment above applies here too.

It may be that we're supposed to invoke Swift with all sources at once
and let it take responsibility for generating the results and doing any
kind of incremental stuff internally.

> - SOURCES doesn't actually exist in CMake, but I saw something called
> OBJECTS which makes me think they are a similar concept.

It shouldn't be too hard to add a <SOURCES> placeholder if needed.  We
may need it either way because we either list all the sources on one
call to swift or on every call to swift.

> - Also, for the second <SOURCES>, I need to remove the one I'm using
> from my -primary-file. And there shouldn't be any non-Swift files in
> the list (no C/C++/Obj-C).

That kind of filtering may be harder to define and require custom logic
in CMake's generators for Swift instead of trying to do it with generic

> - I'm not sure if I'm responsible for the intermediate products
> directories. Do I need to explicitly concat the paths to any of these
> things.

The <OBJECT> placeholder will contain the intermediate directories when
replaced.  We may need new placeholders for other things that go in these
directories for Swift though.

> - I haven't added the bridging header flag/value yet. I need some
> expected variable that holds it.

A target property will likely have to be introduced to hold this.

> Can you give me some suggestions on what to look at next?

Before proceeding with CMake changes I think we need a better
understanding of the tools involved in Swift development.  What
does individual compilation achieve over monolithic compilation?
How does Swift linking interact with other languages?  Etc.

Side note: When we first added Java support to CMake we tried to
make it a builtin language just like C and C++, and even have
rules to tell the generators how to compile each .java -> .class
source separately.  Later we learned that due to nested classes
there can be circular dependencies among .java sources and the
only safe way to compile it is to list all sources at once and
let the compiler handle them internally.  Now Java is used in
CMake through the FindJava and UseJava modules that use custom
commands to do the monolithic compilation.  All the builtin
Java support is pretty much unused because it has never been
ported to the monolithic compilation approach.  I'd prefer not
to repeat such mistakes with Swift.

Given Swift's relationship to ObjC/C++ this may also be time to
revive earlier work posted here (but never finished) on making
OBJC and OBJCXX languages separate from C and CXX in CMake.  This
would be useful if we need to distinguish the languages in order
to properly mix with Swift.


More information about the cmake-developers mailing list