From 07b3439a6c8ea8cccd844b0d5a1ac2532970dfc2 Mon Sep 17 00:00:00 2001 From: Jonathan Wight Date: Tue, 28 Oct 2025 21:17:35 -0700 Subject: [PATCH] Add more options. --- Plugins/MetalCompilerPlugin/MetalPlugin.swift | 24 +++++++++++--- README.md | 33 ++++++++++++++++++- 2 files changed, 52 insertions(+), 5 deletions(-) diff --git a/Plugins/MetalCompilerPlugin/MetalPlugin.swift b/Plugins/MetalCompilerPlugin/MetalPlugin.swift index 8d24222..4df047d 100644 --- a/Plugins/MetalCompilerPlugin/MetalPlugin.swift +++ b/Plugins/MetalCompilerPlugin/MetalPlugin.swift @@ -34,6 +34,7 @@ struct MetalCompiler: Decodable { case metalPath = "metal" case scanInputsInDirectory = "find-inputs" case includeDependencies = "include-dependencies" + case dependencyPathSuffix = "dependency-path-suffix" case inputs = "inputs" case output = "output" case cache = "cache" @@ -42,12 +43,14 @@ struct MetalCompiler: Decodable { case verboseLogging = "verbose-logging" case metalEnableLogging = "metal-enable-logging" case extraEnvironment = "env" + case loggingPrefix = "logging-prefix" } var useXcrun: Bool = true var metalPath: String? var scanInputsInDirectory: Bool = true var includeDependencies: Bool = false + var dependencyPathSuffix: String? var inputs: [String] var output: String = "debug.metallib" var cache: String? @@ -56,6 +59,7 @@ struct MetalCompiler: Decodable { var verboseLogging: Bool = false var metalEnableLogging: Bool = false var extraEnvironment: [String: String]? + var loggingPrefix: String? init(from decoder: any Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) @@ -64,6 +68,7 @@ struct MetalCompiler: Decodable { metalPath = try container.decodeIfPresent(String.self, forKey: .metalPath) scanInputsInDirectory = try container.decodeIfPresent(Bool.self, forKey: .scanInputsInDirectory) ?? true includeDependencies = try container.decodeIfPresent(Bool.self, forKey: .includeDependencies) ?? false + dependencyPathSuffix = try container.decodeIfPresent(String.self, forKey: .dependencyPathSuffix) inputs = try container.decodeIfPresent([String].self, forKey: .inputs) ?? [] output = try container.decodeIfPresent(String.self, forKey: .output) ?? "debug.metallib" cache = try container.decodeIfPresent(String.self, forKey: .cache) @@ -72,6 +77,7 @@ struct MetalCompiler: Decodable { verboseLogging = try container.decodeIfPresent(Bool.self, forKey: .verboseLogging) ?? false metalEnableLogging = try container.decodeIfPresent(Bool.self, forKey: .metalEnableLogging) ?? false extraEnvironment = try container.decodeIfPresent([String: String].self, forKey: .extraEnvironment) + loggingPrefix = try container.decodeIfPresent(String.self, forKey: .loggingPrefix) } } @@ -82,14 +88,18 @@ struct MetalCompiler: Decodable { } func buildCommand(context: PackagePlugin.PluginContext, target: PackagePlugin.Target) -> PackagePlugin.Command { + let prefix = config.loggingPrefix.map { $0 + " " } ?? "" + let logger: ((String) -> Void)? = config.pluginLogging ? { (string: String) in - Diagnostics.remark(string) + Diagnostics.remark(prefix + string) } : nil let verbose: ((String) -> Void)? = config.pluginLogging && config.verboseLogging ? { (string: String) in - Diagnostics.remark(string) + Diagnostics.remark(prefix + string) } : nil + logger?("Current working directory: \(FileManager.default.currentDirectoryPath)") + verbose?("Input environment:") if config.pluginLogging && config.verboseLogging { for (key, value) in ProcessInfo.processInfo.environment.sorted(by: { $0.key < $1.key }) { @@ -141,8 +151,14 @@ struct MetalCompiler: Decodable { case .product: Diagnostics.error("Product dependencies are not supported for include paths in MetalCompilerPlugin.") case .target(let target): - verbose?(" -I \(target.directory.string)") - arguments += ["-I", target.directory.string] + let includePath: String + if let suffix = config.dependencyPathSuffix { + includePath = target.directory.appending([suffix]).string + } else { + includePath = target.directory.string + } + verbose?(" -I \(includePath)") + arguments += ["-I", includePath] @unknown default: Diagnostics.error("Unknown dependency type in MetalCompilerPlugin.") } diff --git a/README.md b/README.md index 753da0b..3397f1f 100644 --- a/README.md +++ b/README.md @@ -70,12 +70,16 @@ All configuration options are optional. Without any configuration file, the plug "xcrun": true, "metal": "/path/to/metal", "find-inputs": true, + "include-dependencies": false, + "dependency-path-suffix": "include", "inputs": ["additional/file.metal"], "output": "debug.metallib", "cache": "/path/to/cache", "flags": ["-gline-tables-only", "-frecord-sources"], "plugin-logging": false, + "verbose-logging": false, "metal-enable-logging": false, + "logging-prefix": "[Metal]", "env": { "TMPDIR": "/private/tmp" } @@ -90,6 +94,10 @@ All configuration options are optional. Without any configuration file, the plug - **`find-inputs`** (boolean, default: `true`): Whether to automatically scan the target directory for `.metal` files. When `true`, all `.metal` files in the target are included. +- **`include-dependencies`** (boolean, default: `false`): Whether to include target dependencies as include paths (`-I`) when compiling. This allows Metal files to import headers from dependency targets. + +- **`dependency-path-suffix`** (string, optional): A path suffix to append to each dependency directory when generating include paths. Useful when headers are in a subdirectory like `include/`. Only applies when `include-dependencies` is `true`. + - **`inputs`** (array of strings, default: `[]`): Additional input files to compile, in addition to those found by scanning (if enabled). - **`output`** (string, default: `"debug.metallib"`): Name of the output metallib file. @@ -98,7 +106,11 @@ All configuration options are optional. Without any configuration file, the plug - **`flags`** (array of strings, default: `["-gline-tables-only", "-frecord-sources"]`): Compiler flags to pass to the metal compiler. The default flags enable debugging in Xcode Metal Debugger. -- **`plugin-logging`** (boolean, default: `false`): Enable verbose logging from the plugin itself for debugging purposes. +- **`plugin-logging`** (boolean, default: `false`): Enable logging from the plugin itself for debugging purposes. + +- **`verbose-logging`** (boolean, default: `false`): Enable more detailed verbose logging. Only takes effect when `plugin-logging` is also `true`. Shows additional details like all environment variables, full command arguments, and input/output file lists. + +- **`logging-prefix`** (string, optional): Custom prefix to prepend to all log messages from the plugin. Useful for distinguishing plugin output in complex build logs. - **`metal-enable-logging`** (boolean, default: `false`): Enable metal compiler logging by adding the `-fmetal-enable-logging` flag. @@ -114,6 +126,16 @@ For basic usage with debugging enabled: } ``` +For verbose debugging with a custom prefix: + +```json +{ + "plugin-logging": true, + "verbose-logging": true, + "logging-prefix": "[MyShaders]" +} +``` + For custom compiler flags: ```json @@ -122,6 +144,15 @@ For custom compiler flags: } ``` +For including headers from dependency targets: + +```json +{ + "include-dependencies": true, + "dependency-path-suffix": "include" +} +``` + ## License BSD 3-clause. See [LICENSE.md](LICENSE.md).