Thanks @jrose !
I wanted to still give my original post a try as an exercise of build plugin. So I ended up creating following BuildToolPlugin:
import Foundation
import PackagePlugin
@main
struct SymlinkGenerationPlugin: BuildToolPlugin {
func createBuildCommands(context: PluginContext, target: Target) async throws -> [Command] {
let outputDirectoryPath = context.package.directory.appending("Sources").appending("include")
let outputDirectory = URL(fileURLWithPath: outputDirectoryPath.string)
let fileManager = FileManager.default
try? fileManager.removeItem(at: outputDirectory)
try? fileManager.createDirectory(atPath: outputDirectoryPath.string, withItermediateDirectories: false)
let inputDirectoryPath = context.package.directory.appending("Sources").appending("ObjCPackage")
return [.buildCommand(displayName: "Generating Symlinks", executable: try context.tool(named: "SymlinkGEneration").path, arguments: [inputDirectoryPath, outputDirectoryPath], environment: [:])]
}
}
Here is the code for SymlinkGeneration:
@main
@available(macOS 13.0.0, *)
struct SymlinkGeneration {
static func main() async throws {
guard CommandLine.arguments.count == 3 else {
throw SymlinkGenerationError.invalidArguments
}
let input = URL(filePath: CommandLine.arguments[1])
let output = URL(filePath: CommandLine.arguments[2])
let fileManager = FileManager.default
if let enumerator = fileManager.enumerator(at: input, includingPropertiesForKeys: [.isRegularFileKey], options: [.skipsHiddenFiles, .skipsPackageDescendants]) {
for case let fileURL as URL in enumerator {
let fileName = fileURL.lastPathComponent
let inputFilePath = fileURL.appending(path: fileName)
let outputFilePath = output.appending(path: fileName)
try? fileManager.createSymbolicLink(at: outputFilePath, withDestinationURL: inputFilePath)
}
}
}
}
enum SymlinkGenerationError: Error {
case invalidArguments
case invalidData
}
Here is my package folder structure:
ObjCPackage:
|- Package.swift
|- Plugin:
|- SymlinkGenerationPlugin.swift
|- Sources:
|- include: (Empty for now. Ideally this should contain generated symlinks)
|- ObjCPackage:
|- Calculator.h
|- Calculator.m
|- SymlinkGeneration:
|- SymlinkGeneration.swift
Here is my Package.swift file:
import PackageDescription
let package = Package(
name: "ObjCPackage",
platforms: [.ios(.v13)],
products: [
.library(
name: "ObjCPackage",
targets: ["ObjCPackage"]
),
],
targets: [
.target(
name: "ObjCPackage",
dependencies: [],
path: "Sources",
publicHeaderPath: "include",
plugins: [
.plugin(name: "SymlinkGenerationPlugin")
]
),
.executableTarget(
name: "SymlinkGeneration",
path: "SymlinkGeneration"
),
.plugin(
name: "SymlinkGenerationPlugin",
capability: .buildTool(),
dependencies: ["SymlinkGeneration"],
path: "Plugin"
)
]
)
The build is failing with error: 1359 Segmentation fault: 11 usr/bin/sandbox-exec -p
The other message printed during build phase is:
(deny file-write*
(subpath \"/users/me/Desktop/ObjcPackage")
)
On further search noticed that we might not be able to create a new file within package but may get it within build folder.
Now I have following questions:
- Is there any way to obtain desired result by using build plugin?
- In build plugin where are the created files stored?
- If symlinks are generated at a different path then how can I refer them in
publicHeaderPat
h parameter within Package.swift
?