Swift static libraries don't copy generated Objective-C header

Hello!

I've been working with Swift static libraries and I noticed an interesting issue. A Swift static library produces a generated Objective-C header (known as *-Swift.h). It makes Swift code accessible from Objective-C. Most of the times, the consumer of the library imports it via the module syntax (@import StaticLibrary) which I guess doesn't create the problem that I am going to describe.

The static library is not visible by Objective-C by default. It requires to write a custom build script that copies the generated Objective-C header from DERIVED_SOURCES_DIR to BUILT_PRODUCTS_DIR/include. Something like this is required:

target_dir=${BUILT_PRODUCTS_DIR}/include/${PRODUCT_MODULE_NAME}/

# Ensure the target include path exists
mkdir -p ${target_dir}

# Copy any file that looks like a Swift generated header to the include path
cp ${DERIVED_SOURCES_DIR}/*-Swift.h ${target_dir}

The process and the problem is better explained in the following blog post.

Why is this required at all? I would like to expose the generated Objective-C header to allow Objective-C code to import the library, but ideally I shouldn't expose the -Swift.h header that users of the library have to import. I also tried to use an umbrella header to import the generated interface and not copy it to the public headers folder but the compiler is not able to find the generated -Swift.h when importing it.

My ideal solution would be to create an umbrella header (or have it automatically be generated) and import a Swift static library like:

#import <MyLibrary/MyLibrary.h>

Any input is appreciated!
Patrick

I haven't tried this before. But I can give you a clue about how to generate a header file.

Type this in Terminal:

xcrun swiftc --help

or

swift --help

You can find

-emit-objc-header-path <path>
                       Emit an Objective-C header file to <path>
-emit-objc-header      Emit an Objective-C header file

If it works can you reply the effect of the command.

I know about that command, and the compiler already uses that behind the scenes to generate the header. I am wondering why it's not included in the static library by default but it requires a build script to move that file to the final bundle.

Most of the Swift/ObjC interop support in Xcode is built around modules, and most of that support is built around frameworks. With modules, just a plain header isn't enough to describe the full interface of a library, because the C compiler has no guarantee that that header is standalone. However, Xcode doesn't know how to generate module maps for plain libraries at the moment, though you could write one yourself in theory.

I do think it's a reasonable feature request to not have the generated header languish in DerivedSources, though. Can you file a bug against https://bugreport.apple.com?

Meanwhile, though there's no template for it, you can build a "static framework" by using the framework target template and changing the product type to a static library. Keep in mind that this opts you into the other downsides of static libraries (though nothing more than what you'd see with the regular static library target), and that there may still be issues with this.

Hey @jrose! Thanks for the explanation. I will file a bug report since I think this is a reasonable expectation for projects heavily using static libraries. The bug you mentioned is something that I filed myself a couple of months ago, is there any progress on it?

Filed rdar://47592203 as requested.

No progress, sorry. ABI stability's been claiming a lot of time from a lot of the regular Swift contributors.