Commit 089ebe8b authored by Drew's avatar Drew

Add `umbrella-header` to specify umbrella headers

This is essentially the same as a "bridging" header, except without any
ObjC (straight C).  Upstream says it "can't be done"; let's see if Linux
CI likes this implementation.  Take *that*, anonymous compiler engineers.

My motivation for this patch is essentially as a workaround for SR-655.

https://bugs.swift.org/browse/SR-655

That is to say, I want to call some arbitrary C code, but due to that
bug, I can't hide my C code behind a module / modulemap.

Instead what I can do is just `#include <whatever>` in my umbrella
header, and then the C imports are available to Swift.

Internally, we emit a modulemap based on the umbrella header and then
inject some compile flags (notably, `-import-underlying-module`) to make
it load.  This is the design I reverse-engineered from Xcode.  That
notwithstanding, it seems to be based entirely on public APIs and I
guess we'll find out if it works on Linux.

While my motivation is based on C imports, umbrella headers may be
useful wherever Swift projects are sold.  There are multiple features
that get unlocked here, including access to the C preprocessor.
parent ed20b04e
Pipeline #997 failed with stage
......@@ -199,6 +199,7 @@ final class ATllbuild : Tool {
case XCTestify = "xctestify"
case XCTestStrict = "xctestStrict"
case PublishProduct = "publishProduct"
case UmbrellaHeader = "umbrella-header"
static var allOptions : [Options] {
return [
......@@ -216,7 +217,8 @@ final class ATllbuild : Tool {
SwiftCPath,
XCTestify,
XCTestStrict,
PublishProduct
PublishProduct,
UmbrellaHeader
]
}
}
......@@ -240,9 +242,12 @@ final class ATllbuild : Tool {
//multiple invocations of atllbuild.
let _ = try? manager.removeItemAtPath(workDirectory + "/objects")
let _ = try? manager.removeItemAtPath(workDirectory + "/llbuildtmp")
let _ = try? manager.removeItemAtPath(workDirectory + "/include")
let _ = try? manager.createDirectoryAtPath(workDirectory, withIntermediateDirectories: false, attributes: nil)
let _ = try? manager.createDirectoryAtPath(workDirectory + "/products", withIntermediateDirectories: false, attributes: nil)
let _ = try? manager.createDirectoryAtPath(workDirectory + "/objects", withIntermediateDirectories: false, attributes: nil)
let _ = try? manager.createDirectoryAtPath(workDirectory + "/include", withIntermediateDirectories: false, attributes: nil)
//parse arguments
var linkWithProduct: [String] = []
......@@ -304,6 +309,21 @@ final class ATllbuild : Tool {
guard let name = task[Options.Name.rawValue]?.string else { fatalError("No name for atllbuild task") }
if let umbrellaHeader = task[Options.UmbrellaHeader.rawValue]?.string {
var s = ""
s += "module \(name) {\n"
s += " umbrella header \"Umbrella.h\"\n"
s += "\n"
s += " export *\n"
s += " module * { export * }\n"
s += "}\n"
try! s.writeToFile(workDirectory+"/include/module.modulemap", atomically: false, encoding: NSUTF8StringEncoding)
try! manager.copyItemAtPath(umbrellaHeader, toPath: workDirectory + "/include/Umbrella.h")
compileOptions.append("-I")
compileOptions.append(workDirectory + "/include/")
compileOptions.append("-import-underlying-module")
}
let bootstrapOnly: Bool
if task[Options.BootstrapOnly.rawValue]?.bool == true {
......
#define C_FLAG 1
\ No newline at end of file
(package
:name "umbrella_header"
:tasks {
:default {
:tool "atllbuild"
:source ["foo.swift"]
:name "UmbrellaHeader"
:outputType "static-library"
:umbrella-header "UmbrellaHeader.h"
}
}
)
\ No newline at end of file
func foo() {
print(C_FLAG)
}
\ No newline at end of file
......@@ -10,6 +10,10 @@ pwd
echo "****************SELF-HOSTING TEST**************"
$ATBUILD atbuild
echo "****************UMBRELLA TEST**************"
cd $DIR/tests/fixtures/umbrella_header
$ATBUILD
echo "****************PUBLISHPRODUCT TEST**************"
cd $DIR/tests/fixtures/publish_product
$ATBUILD
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment