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

Eric Wing ewmailing at gmail.com
Wed Jan 13 18:17:45 EST 2016


>> 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.

I suspect it is like C++ and C. If there is both, you promote up to C++ linking.
So if there is any .swift file or library in the mix, you need to
promote up to use Swift.

Under the hood, I think the LLVM linker can handle all of these
through ld. But I think the thing that is tripping me up is that Swift
seems to need to link against some additional libraries which are not
needed in the pure C case. The swiftc command seems to know how to
automatically link in those extra dependencies (and I don't need to
add all the search paths to where the Swift core libraries are
located).

Anyway, I tried bumping up CMAKE_Swift_LINKER_PREFERENCE to 40. (Same
as Java). But it didn't seem to do anything for me.

I then added to my test CMakeLists.txt:
set_property(TARGET MyApp PROPERTY LINKER_LANGUAGE Swift)

That then worked, but I'm confused how to get CMake to automatically
do this for me because I expected CMAKE_Swift_LINKER_PREFERENCE to do
this.


>
> 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.

Unfortunately, there isn't a whole lot more information. The majority
of the examples are hello world programs with one file.

The best write up I've seen is this series:
http://owensd.io/blog/compiling-swift-without-xcode/
http://owensd.io/blog/compiling-individual-files/
http://owensd.io/blog/swift-vs-swiftc/
http://owensd.io/blog/swift-makefiles---take-2/

One interesting note, swiftc is just an alias for swift.


The exception is the Swift Package manager. But this is a convention
based system. Right now it is far from finished and its conventions
are actually incompatible with Xcode. It has its own file format and
also requires all dependency packages be in a Git repo and follow a
certain tagging convention. I also haven't seen any way to directly
mix C+Swift code in a module and they expect you to create a separate
module for C stuff which you then import in. I'm under the impression
they plan to relax a lot of these things, but I find it currently too
incomplete and with too much impedance to be useful right now.

(By the way, I think I'm a little incorrect about main.swift being
special. I'm seeing examples where they name the file anything.swift.
It looks like Swift will automatically create a main entry point for
you when building an executable, especially in the one-shot case. With
swiftc it must be a one-shot otherwise you get duplicate symbols. With
swift -frontend, it some how manages to create one. But with the Swift
Package system, I think main.swift is a convention-requirement.)



> 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.

So Xcode is using the swift -frontend technique and it looks like it
doing it incrementally. I think the requirement for the list of other
files is so it can resolve the dependencies.


> 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.

Right.

>> - 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
> placeholders.

I just tried not filtering the current primary file from the list. It
still worked. So maybe we can get away with not filtering that.
However, we do need to filter any C files. That didn't work. (It tried
to compile those .c files as Swift which obviously won't work.)



>> 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?

I'm actually not sure. The monolithic one-shot should avoid any
potential incorrectness problems if a dependent file was changed but a
calling file wasn't recompiled. I don't know if Swift has these types
of problems like C or if it is immune.

It feels like Xcode is doing some incremental building or caching for
me by doing individual compilation. However, it seems to recompile
both files in the log. But Xcode is using a bunch of other switches
and temporary files that may be assisting this.


> How does Swift linking interact with other languages?  Etc.

So as I mentioned, ld seems to be able to handle all the .o files
regardless of language and link them. The constraint seems to be that
Swift adds some additional dependencies.

I think I read a claim that somebody linked to .o files created by gcc
instead of clang. I probably wouldn't recommend this, but it suggests
there isn't anything that special by the time we reach this stage.


> 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.

So I think we will need that list of all sources for Swift because
like Java, there are no header files so the compiler needs to resolve
dependencies.

For the moment, I like swiftc over swift because it seems a lot
simpler. I hope this means the least changes for CMake right now.

I won't lie to you. In maybe two years, the Swift Package Manager will
probably be closer to finished/stable and we may need to re-evaluate
things. I suspect there will be a temptation to invoke it because it
will have the ability to download dependencies from the internet on
the fly. However, it's still too early for me to guess how this is
going to interoperate with C code, local libraries, bundling
resources, packaging and codesigning for distribution. One story is
that this will completely sub-plant the need for something like CMake.
Another story is that the Linux/Swift effort initially seems to be
focused on server/headless backends which doesn't need a lot of the
same things as front-end applications. So Xcode and CMake still may be
needed and people may find the Package Manager isn't useful outside
server apps. (It currently reminds me a little of Go's system which is
also heavily server focused.)


> 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.
>

Maybe, but I think we can punt on that for two reasons.
1) As I said, the LLVM linker seems to handle all these already more
or less transparently. For Swift, we just need to separate Swift files
from everything else.

2) The open source Swift release does not include Obj-C. They are
pushing a pure Swift solution for everybody else.

Since the Xcode generator for Swift more or less works*, I think that
is the proper way using Swift on Mac/iOS. That already handles a lot
of esoteric platform stuff better and also handles the Obj-C/Obj-C++
more correctly.

*By the way, I found two minor issues... (1) Swift has additional
separate flags for some things like optimization settings: we need to
duplicate the CMake Debug/Release/MinSizeRel/RelWithDebug flags for
the Swift section, (2) Everytime I create a new Xcode/Swift project, a
prompt comes up telling me my Swift version is 1.x and the wizard will
help me migrate my code to the latest. I suspect there is some version
flag in the generated Xcode project that needs to be bumped up.


Anyway, it seems like adding SOURCES is the next step. Any hints on
how to do that?

Thanks,
Eric


More information about the cmake-developers mailing list