Is there a way to list the APIs provided by my dynamic library?

What I'm trying to achieve

A Swift user should be able to build a dynamic library with Swift and use it anywhere - in apps written in other programming languages. Simple C types like integers seem to be the least common denominator that are supported in most programming languages. So a function like this

@_cdecl("meaningOfLife")
public func meaningOfLife() -> Int {
    return 42
}

should be callable from an app written in a language other than Swift. What is missing here for a programmer who wants to call this function from their non-Swift app, is a separate file with a list of APIs available in the library.

How I did it in the past

I use swiftc compiler. In the past I passed the -emit-clang-header-path parameter to it, with C++ interoperabiliy turned on. This generated a header (.h) file that contained the desired list of APIs. In C and C++ it could be directly used by C/C++ compiler, and for programmers using other languages it provided a way to reason about available APIs and write language-specific bindings.

I don't use this approach anymore for the following reasons:

  • In recent versions of Swift this parameter is not listed in the output of swiftc -help, nor even swiftc -help-hidden.
  • In Swift 6 it still works, but for the simple source code above it produces an enormous header file (170K, 5390 lines) full of C++ interoperability things. Obviously not what I want.
  • For this approach C++ interoperability should be turned on (or else only Objective-C compatible header file is emitted). As of Swift 6.0.1 C++ iteroperability does not work on Windows.

How I do it now

Now I use similar -emit-objc-header-path command-line parameter. It is documented in swiftc -help, creates a header file of reasonable size (10K, 313 lines), and does not require C++ interoperability mode. What I don't like is the fact that Objective-C header file is hardly of any direct use, especially on Windows. It can only serve as a reference for writing another language-specific bindings, and for this purpose it is not very convenient.

What else I tried

In Swift 6 there is another command-line option: -emit-api-descriptor-path, which looks like exactly what I need. But for the source code above it produces the following:

{
  "target": "x86_64-unknown-windows-msvc",
  "globals": [
    {
      "name": "$s14dynamicLibrary13meaningOfLifeSiyF",
      "access": "public",
      "file": "dynamicLibrary.swift",
      "linkage": "exported"
    },
    {
      "name": "meaningOfLife",
      "access": "public",
      "file": "dynamicLibrary.swift",
      "linkage": "exported"
    }
  ],
  "interfaces": [],
  "categories": [],
  "version": "1.0"
}

I can live with the mysterious $s14dynamicLibrary13meaningOfLifeSiyF, but as for the meaningOfLife() -> Int function, this JSON does not mention that the function returns an Int, and thus is completely useless for my purpose.

The question

Is there a way to list the APIs provided by my dynamic library (other than Objective-C header file)?

1 Like