Skip to content

Provide an API to fetch compilation arguments from SwiftPM's build system for use in another build system #9511

@abdulowork

Description

@abdulowork

Description

Hi folks. We in the Kotlin team are building support for importing SwiftPM dependencies that expose Objective-C and C APIs for our Kotlin/Native backend in our primary build system: Gradle.

Our Kotlin/Native backend uses libclang to understand Objective-C headers and modulemaps, so to import SwiftPM dependencies, we want to obtain the same arguments the build system with SwiftPM support would pass to clang -x objective-c compilation. Namely, we are interested in:

  • Search paths such as -I and -F
  • Modulemap paths such as -fmodule-map-file=
  • Macro definitions

A bit beyond regular clang arguments, we are also interested in some prerequisites of the Objective-C compilations in SwiftPM:

  • Particularly in the case of Swift, we want to see TargetName-Swift.h files produced by the Swift compiler during swiftc -emit-objc-header
  • One of the main use cases we want to support is the import of libraries like GoogleMaps, so we need some way to get to the proper slice of the headers packaged in SwiftPM’s .binaryTarget

At the moment, what we do is:

  1. We generate a Package.swift with all the dependencies we want to import in a fake Objective-C SwiftPM target
  2. Then we run the build: DUMP_PATH=/path/to/dump_dir xcodebuild -destination “generic/platform=...” ARCHS=... CC=compilerArgumentsDumpScript.sh for each of the target platforms that we are interested in
  3. Finally, we find the right clang call, parse all the necessary compiler arguments and call our libclang machinery

This works for us in general; however, there are a couple of issues. First, I don’t understand how reliable this CC override is for inferring the clang arguments. I see that, for example, the SWIFT_EXEC override now also requires SWIFT_USE_INTEGRATED_DRIVER=NO. I imagine the CC override might break for us in the future and could also change the build system behavior.

The second issue is that we want the libclang initialization to be as fast as possible, as we run it in our IDE import pipeline to show completions for Objective-C APIs in the Kotlin code. So, for example, when we run libclang, we don’t need any machine code that is produced by the swiftc/clang compilations, but we do need to see all the headers. I expect we can improve import performance if SwiftPM and Swift Build could disable IDE-irrelevant steps.

Please let me know if an e2e example would be helpful! I can publish a sample of how we do this right now in the Kotlin Gradle Plugin.

Do you think SwiftPM and/or Swift Build could offer APIs to expose all this information and maybe even provide some customization for the IDE use case? I imagine it would also be valuable for any other build systems and/or languages that interoperate with C/Objective-C using libclang. Perhaps a similar mechanism could also help Swift interoperability in the future by exposing the Swift compiler arguments to another build system, allowing it to use parts of the Swift compiler for the interop?

Expected behavior

No response

Actual behavior

No response

Steps to reproduce

No response

Swift Package Manager version/commit hash

No response

Swift & OS version (output of swift --version && uname -a)

No response

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions