Is there a way to emit C/C++ header?

When building a dynamic library intended to be used with a host application written in C/C++, is there any way to generate a C/C++ header file?

A public function can be declared with the @_cdecl("functionName") attribute and have a C calling convention.

The swiftc compiler can be invoked with the -emit-objc-header command line argument, and in this case a header file is created, but it's an Objective-C header file, and I believe it's not compatible with C/C++.

Now that C/C++ interoperability is actively developing, is there a way to emit a C/C++ header file?

1 Like

I've been wondering this too, a bit. It'd be nice to be able (eventually) to produce good-quality C++ APIs atop Swift code. I like to think it opens some doors for using Swift for core implementations while supporting C++ users, rather than the other way around.

1 Like

Quoting Setting Up Mixed-Language Swift and C++ Projects from

The -emit-clang-header-path Swift frontend flag can be used to emit a generated header when exposing Swift APIs to C++ when building Swift code in a build system that doesn’t provide automatic support for generating a header file with exposed APIs.

The following Swift compiler invocation emits a generated header file for the SwiftModule module that consists of two source files, a.swift and b.swift:

swiftc -frontend -typecheck \
       /sources/a.swift /sources/b.swift -module-name SwiftModule \
       -cxx-interoperability-mode=default \
       -emit-clang-header-path SwiftModule-Swift.h

I haven’t tried this.


It works. The -emit-clang-header-path does the trick.
But there are concerns, at least for me:

  1. This command line parameter seems to be undocumented. The swiftc --help command does not mention it.
  2. The -cxx-interoperability-mode=default command line parameter is required to emit Objective C/C/C++ compatible header file. Without it only Objective C header is emitted.

Why I'm uncomfortable with the C++ interoperability flag is because modules built with this flag used to be binary incompatible with modules built without it (they seem to be compatible as of Swift 5.10, which is great). And I tend to import precompiled modules (as dynamic libraries) rather than recompile all dependencies every time. Thanks a lot anyway @ole!