This PR lets you mix .swift, .h, and .c files all in the same atllbuild task. It works a lot like Xcode's behavior, if you've used that.
\# Rationale
I feel the need to defend this feature, since I have been previously on the record as saying "the entire value is debatable" (https://www.mail-archive.com/swift-evolution@swift.org/msg01829.html).
There are 5 cases where I think it makes sense to add a little C to your Swift project:
* To use the odd feature Swift doesn't support. Recently, I needed to call a variadic C function; Swift cannot call them, C is our only hope
* To work around a Swift compiler bug. Several of my projects have this case.
* To repackage an existing Xcode project where somebody used C in it. I have not investigated and don't want to investigate whether that somebody was sane or insane, but we should at least be able to build their project.
* To include headers from a system C library. SwiftPM tries to solve this with module maps, however it doesn't hide the implementation details https://bugs.swift.org/browse/SR-655. This feature can actually hide them with a few different methods discussed below, which is a clear win.
* To write Swift bindings for a C library. This generally involves a little C glue code (such as using a header or something), and for reasons that will become clear, using our C support is better than previous approaches at that problem.
\# Rationale-NOT:
Additional rationale:
* SwiftPM will probably add this eventually
* per #113, we should be a superset of their functionality
I would like to be very clear about my goals:
* This is really only designed for the case of "need a little C in your Swift project", not anything larger
* This is not a replacement for e.g. GNU Make or a general-purpose C buildsystem, nor will it become one
* The preferred mechanism for building a real C library is shelling out to your real C buildsystem
* Nobody should be repackaging their established C libraries as atllbuild tasks. atllbuild is designed to build Swift projects, not C projects.
\# Design
* You can now specify `.c` and `.h` files in the sources for atllbuild tasks
* Also `**.c` and `**.h` just like `**.swift`
* Like `.swift`, no files are scanned by default, everything is explicit
* Adding `.c` files causes them to be compiled and linked into the atllbuild task just like swift files
* Adding `.h` files exposes declarations to Swift. It works much like a bridging header; put stuff in header files and then Swift code will see it.
* Your `.h`s can import other `.h`s (from the system, or anywhere else) and you otherwise have access to the complete C preprocessor
* New atllbuild setting `c-compile-options` specifies compile options for C files. `compile-options` is ignored for C.
* C files work as you'd expect, including support for things like configurations, optimization, atbuild preprocessor macros, etc.
\# Linking
The standard `link-options` sets link options for both C and Swift; since they are linked into the same library there is no individual control. So if you want to link your C (and Swift) code against curl, you could say `:link-options ["-lcurl"]` for example.
The problem with this approach is that everybody who depends on you might also need `-lcurl`. Traditionally we've solved this with overlays that we expose to callers.
SwiftPM avoids this problem by requiring everyone to create e.g. `CCurl` everywhere: https://github.com/apple/swift-package-manager/blob/master/Documentation/SystemModules.md
And in fact people do: https://github.com/IBM-Swift/CCurl
The problem is now you have to import `CCurl` everywhere (even in files that don't directly use it). See generally, https://bugs.swift.org/browse/SR-655, https://gist.github.com/briancroom/5d0f1b966fa9ef0ae4950e97f9d76f77
Here is the cool part though. This PR adds a new option `:module-map-link ["curl"]`. That will inject a link directive into both the module map we use at buildtime and the one we export e.g. into an atbin.
Emitting that link directive has the effect of injecting `:link-options ["-lcurl"]`. However, it will *also* inject that link option into any Swift module that imports this one. The result is that downstream no longer needs to add `:link-options ["-lcurl"]` anymore.
Additonally, since we achieve this in a single module, there is no `CCurl` to import anymore. The details of linking to the C library are more effectively hidden.
For these reasons, I believe using the C support in this PR is way more effective for writing bindings than any other solution.
\# Known issues
* Using `.h` in `sources` requires a synthesized module map
* Using `.c` in `sources` is not supported for bitcode
* Using `module-map-link` requires the module map to be distributed for the link to take effect on downstream; we recommend `packageatbin` for packing build products
* Currently, swift functions are not "visible" to C code (like they are visible to ObjC from Xcode) although presumably if you had a function, knew its calling convention, and knew its c-name, you could totally call it from C.