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

Brad King brad.king at kitware.com
Fri Jan 8 11:30:44 EST 2016


On 12/24/2015 06:13 AM, Eric Wing wrote:
> Now that Swift is officially open source and already available for
> Linux, I started looking at the build process on Linux which I hope we
> can figure out how to incorporate into the CMake Makefile generator.

Thanks for digging in to this!

> To start with, there actually seem to be two different approaches.
> 1) The swiftc command line compiler (similar to gcc, clang with
> switches and output that seem to resemble them as well)
> 2) A formal package/module system for Swift which works with a Swift
> command line build tool ‘swift build’
> 
> So far, for my usage cases, I’ve found the (2) package/module system
> to be annoying and a bunch of indirection and extra steps. I also
> don’t feel I have completely wrapped my head around it, so I’m not
> going to focus on this for now. However, as more pure Swift libraries
> get written, I think interoperating with the module system will become
> extremely important, which we’ll ultimately need to deal with.

Yes.  A few months ago I spent a few hours looking at the commands Xcode
uses to build Swift code.  For reference, here are some notes I took
(not well organized):

----------------------------------------------------------------------------
MergeSwiftModule produces .swiftmodule files, which seem to be serialized
copies of swift modules, like binary headers, each covering an entire module
over multiple source files.  MergeSwiftModule merges partial modules from
individual sources into one for the whole module.

The .swiftmodule for a shared library can be consumed while compiling
other projects whose "import" statements search the -I path for the
.swiftmodule files.  The .swiftmodule file is a binary header for the
whole shared library.

The compiler leaves in .o files a decl that tells the linker what libraries
to link.  The linker hopefully tolerates seeing those libraries explicitly
on the command line too, since CMake will generate those.

Swift does have conditional compilation that affects imports.

See the -emit-dependencies and output file map options to control where .d
files are generated.

swift -help
swift -help-hidden
swift -frontend -help
swift -frontend -help-hidden

If one imports a library written in C/objc then something generates a
module map pointing to the headers.  It seems to lazily generate from
the headers a module that can be loaded.  To use a C library from Swift
one must write a module map explicitly.  Some lib providers may support
modules directly and provide the module map next to the library file.

----------------------------------------------------------------------------

> But in the meantime, back to (1) swiftc, this I found much more
> straight-forward, at least for dealing with C code and C libraries and
> I think maps pretty well to the current CMake design.

Great.

> There is a pretty good example/write up found here:
> http://dev.iachieved.it/iachievedit/more-swift-on-linux/

Good link.

> For a Swift application that also has C code, and uses C libraries,
> this is the basic procedure:
> 
> 1) Compile the C files into .o
> clang -c escapetext.c
> 
> 2) Compile the Swift files into .o (note: The header seems to be the
> ‘Bridging Header’ discussed in the prior thread)
> swiftc -c escapeswift.swift -import-objc-header escapetext.h
> 
> 3) Link all the object files together to build the final app executable
> swiftc escapeswift.o escapetext.o -o escapeswift -lcurl

Okay.

> (Note: ‘main.swift’ seems get
> special handling by the swift compiler and is always treated as your
> application entry point.)

Yes, that seems to be the case.  Furthermore the file can just have
code directly in the top level because the whole thing is the "main"
function.

> So I’d like to talk about how to further enhance CMake to do the above.

Okay.  Ideally I'd like a solution designed with understanding of the
module system as mentioned in my notes above.

> In my head, for the above examples, I think I would want to do
> something like:
> 
> find_package(SDL)
> include_directories(${SDL_INCLUDE_DIR})
> 
> # Forgot if we already had a convention for controlling this in the
> Xcode generator
> set(SWIFT_BRIDGING_HEADER SwiftSDL-Bridging-Header.h)

As you noted in another response, we have a per-target property
XCODE_ATTRIBUTE_SWIFT_OBJC_BRIDGING_HEADER.  The bridging header
does need to be per-target, yes.

> add_executable(MyAppExe
> 	SDLSwiftBinding.c
> 	main.swift
> 	MyApp.swift
> )
> target_link_libraries(MyAppExe ${SDL_LIBRARY})

Yes, that looks like what we want to achieve.

Thanks,
-Brad



More information about the cmake-developers mailing list