How to import macros using methods other than SwiftPM

I'm trying to import macro functionality using CocoaPods, but Xcode is giving an error:

 External macro implementation type 'XXX' could not be found for macro 'XXX'; the type must be public and provided by a macro target in a Swift package, or via '-plugin-path' or '-load-plugin-library'. 

How can I resolve this?
I haven't found any articles about '-plugin-path' or '-load-plugin-library

2 Likes

You can add flag -load-plugin-executable <path>#<modulename> to OTHER_SWIFT_FLAGS via the post_install hook in the Podfile.
The executable file you can find in the build folder of your swift package with the target macro

1 Like

I tried this method, but it doesn't seem to work. Did I misunderstand something?
I have currently created a new target that depends on SwiftSyntax through CocoaPods. Within this target, I've defined macros that compile successfully. However, unlike SPM, it cannot be used externally
Even though macro expansion has been achieved, compilation still results in errors

and this is my build settings:

-load-plugin-library needs to point to the build folder that contains your compiled macros, not your source folder.

yes, the path (/Users/lifangchang/.../_IcarusMacros) points to the binary executable file compiled using the 'swift build' command within the SPM directory.

You don't need to depend on SwiftSyntax in your main project, it's just a part of macro, that runs in external sandbox.
Now, you need to define macro through #externalMacro in your IcarusDemo target.

macro icarusCodable =
    #externalMacro(module: "IcarusMacros", type: "AutoCodableMacro")

Note that, currently, the only supported way of using macros is using SwiftPM's .macro target. Compiler options related to macro plugins are not guaranteed to be stable, nor officially documented. It is possible to make macro plugin manually and use it if really want, but again it's not guaranteed to be stable.

Does your macro work in SwiftPM? If not, or you haven't tried it, I'd recommend to make it work in SwiftPM first, then port it using CocoaPods.

When making macro plugin manually (not using SwiftPM), check these things:

  • Macro plugin target must be an executable target.
  • Macro plugin target must be built for "host" platform, not the application "target". I.e. macOS not iOS.
  • Macro plugin target must import SwiftCompilerPlugin and declare @main type conforming to CompilerPlugin, and define providingMacros listing the providing macro types. E.g.
    import SwiftCompilerPlugin
    
    @main
    struct IcarusMacros: CompilerPlugin {
      var providingMacros: [Macros.Type] = [
        IcarusCodable.self
      ]
    }
    
  • Specify -load-plugin-executable <path>#<modulename> to the user targets. i.e. the module that declares macro icarusCodable = #externalMacro(...), and the actual users of @icarusCodable. Where <path> is the built plugin target executable and <modulename> is the Swift module name of the plugin target.
5 Likes

Are there any blockers to publicizing and documenting the driver flags for passing in macros?

IMO, there should not be any public-facing officially supported language features that are only accessible through SwiftPM or through an -Xfrontend backdoor flag; the swiftc driver interface for this should be stabilized at the same time as the rest of the feature set.

11 Likes

Thank you for your response. My macros can be compiled and run on Swift Package Manager. I will try the methods you provided.

does the method work for you? I still got a error as the beginning.

External macro implementation type 'XXX' could not be found for macro 'XXX'; the type must be public and provided by a macro target in a Swift package, or via '-plugin-path' or '-load-plugin-library'.

This solution works for me, allowing the use of macros in projects without relying on SPM

1 Like

I know this is cheeky but did you create a simple project to test this … that maybe you could share? [Insert sad puppy gif here]

This is a very simple demo.

I hope this can be of help to you.
MacrosDemo/LFCMacroMacros is the binary product after macro compilation. You can execute 'swift build -c release' in the root directory of the macros, and then find it in the 'build' directory
@Snow @jjrscott

2 Likes

Thanks. I've made my own which uses the bare minimum from SwiftSyntax to build macros. I assume a combination of the two would produce a functional project devoid of either SPM or SwiftSyntax.

Any idea why Xcode won't show Expand Macro option in the following case?

Context:

Module - MacroLib has the macro declaration.

@freestanding(expression) public macro stringify<T>(_ value: T) -> (T, String) = #externalMacro(module: "MacroExamplesPlugin", type: "StringifyMacro")

This module is pre-compiled and is added as -I to the client module: MacroClient.

import MacroLib

func test() {
 #stringify(1 + 2)
}

MacroClient builds all fine, is able to make use of macros with no issues. However, Expand Macro option is now shown.

When we don't pre-compile the MacroLib module and focus it along with MacroClient, Expand Option is all shown as expected.

Especially in large projects, giving developers a focused project to their workflow is a use-case that we support, and are interested to know if there is a workaround for the above.

cc: @rintaro @ahoppen

1 Like

@chiragramani Do you have a sample project and steps to reproduce the issue? How do you pre-compile the macro? Do you set any specific compiler arguments in the client project so that it finds the pre-compiled macro?

Thanks @ahoppen. Here is the sample project with the repro steps. GitHub - chiragramani/SwiftMacroRepro

Please let me know if you see any issues in setting it up.

1 Like

Thank you for the reproducer. I confirmed the symptom, and it turned out that this is a Xcode issue but not a Swift (or SourceKit) issue. Could you file a feedback (https://feedbackassistant.apple.com/)?

(As a workaround, Refactor > Inline Macro still should work)

Thank you for looking into it and appreciate your timely response and help on this issue!

https://feedbackassistant.apple.com/feedback/13188847

1 Like