diff --git a/src/Cargo.UnitTests/CargoTest.cs b/src/Cargo.UnitTests/CargoTest.cs index 6d66141..66e6705 100644 --- a/src/Cargo.UnitTests/CargoTest.cs +++ b/src/Cargo.UnitTests/CargoTest.cs @@ -190,6 +190,8 @@ public void ProjectsCanDependOnEachOtherProjects() [Theory] [InlineData("AutomaticallyUseReferenceAssemblyPackages", "true", "true")] [InlineData("AutomaticallyUseReferenceAssemblyPackages", null, "false")] + [InlineData("CargoProfile", "release-windows", "release-windows")] + [InlineData("CargoProfile", null, "")] [InlineData("DebugSymbols", "true", "false")] [InlineData("DebugSymbols", null, "false")] [InlineData("DebugType", "Full", "None")] @@ -217,6 +219,9 @@ public void ProjectsCanDependOnEachOtherProjects() [InlineData("SkipCopyFilesMarkedCopyLocal", "false", "false")] [InlineData("SkipCopyFilesMarkedCopyLocal", "true", "true")] [InlineData("SkipCopyFilesMarkedCopyLocal", null, "")] + [InlineData("MsRustupTargets", "aarch64-pc-windows-msvc", "aarch64-pc-windows-msvc")] + [InlineData("MsRustupTargets", "aarch64-pc-windows-msvc;x86_64-pc-windows-msvc", "aarch64-pc-windows-msvc;x86_64-pc-windows-msvc")] + [InlineData("MsRustupTargets", null, "")] public void PropertiesHaveExpectedValues(string propertyName, string value, string expectedValue) { ProjectCreator.Templates.CargoProject( diff --git a/src/Cargo/CargoTask.cs b/src/Cargo/CargoTask.cs index d5d7a8a..03913c0 100644 --- a/src/Cargo/CargoTask.cs +++ b/src/Cargo/CargoTask.cs @@ -103,6 +103,19 @@ private enum ExitCode /// public string CargoOutputDir { get; set; } = string.Empty; + /// + /// Gets or sets an optional Cargo profile to pass to cargo as "--profile <value>" for MSRustup. + /// When set, this overrides the behavior of deriving the profile from Configuration. + /// + public string CargoProfile { get; set; } = string.Empty; + + /// + /// Gets or sets an optional semicolon-separated list of additional target triples to install when running "msrustup toolchain install" + /// (e.g. "aarch64-pc-windows-msvc;x86_64-pc-windows-msvc"). Each value is passed to MSRustup as "--target <triple>". + /// Use this to enable cross-compilation. + /// + public string MsRustupTargets { get; set; } = string.Empty; + /// public override bool Execute() { @@ -178,7 +191,7 @@ private async Task ExecuteAsync() foreach (var registry in GetRegistries(Path.Combine(RepoRoot, _cargoConfigFilePath))) { - var registryName = registry.Key.Trim().ToUpper(); + var registryName = registry.Key.Trim().ToUpper().Replace('-', '_'); _cargoRegistries.Add(registryName); var tokenName = $"CARGO_REGISTRIES_{registryName}_TOKEN"; AddOrUpdateEnvVar(tokenName, $"Bearer {val}"); @@ -247,13 +260,7 @@ private async Task CargoRunCommandAsync(string command, string args) if (!string.IsNullOrEmpty(customCargo)) { - bool isDebugConfiguration = true; - if (!Configuration.Equals("debug", StringComparison.InvariantCultureIgnoreCase)) - { - isDebugConfiguration = false; - } - - return await ExecuteProcessAsync(GetCustomToolChainCargoBin() !, $"{command} {args} --offline {(isDebugConfiguration ? string.Empty : "--" + Configuration.ToLowerInvariant())} --config {Path.Combine(RepoRoot, _cargoConfigFilePath)}", ".", _envVars); + return await ExecuteProcessAsync(GetCustomToolChainCargoBin() !, $"{command} {args} --offline {GetMsRustupProfileArgument()} --config {Path.Combine(RepoRoot, _cargoConfigFilePath)}", ".", _envVars); } return ExitCode.Failed; @@ -262,6 +269,28 @@ private async Task CargoRunCommandAsync(string command, string args) return await ExecuteProcessAsync(_cargoPath, $"{command} {args}", ".", _envVars); } + /// + /// For MSRustup, determines the appropriate Cargo profile argument to pass based on the CargoProfile and Configuration properties. + /// + /// The Cargo profile argument string, if needed; else an empty string. + private string GetMsRustupProfileArgument() + { + // Explicit CargoProfile wins over the Configuration-derived value. + if (!string.IsNullOrEmpty(CargoProfile)) + { + return $"--profile {CargoProfile}"; + } + + // No flag for the default (Debug) profile. + if (string.IsNullOrEmpty(Configuration) || Configuration.Equals("debug", StringComparison.InvariantCultureIgnoreCase)) + { + return string.Empty; + } + + // Use the Configuration as a Cargo profile shorthand (e.g. "--release"). + return "--" + Configuration.ToLowerInvariant(); + } + private async Task DownloadAndInstallRust() { try @@ -643,7 +672,7 @@ private async Task InstallRust() AddOrUpdateEnvVar("MSRUSTUP_PAT", val); } - exitCodeLatest = await ExecuteProcessAsync(rustUpBinary, $"toolchain install {GetToolChainVersion()}", StartupProj, _envVars); + exitCodeLatest = await ExecuteProcessAsync(rustUpBinary, $"toolchain install {GetToolChainVersion()}{GetMsRustupTargetArgs()}", StartupProj, _envVars); if (exitCodeLatest == ExitCode.Succeeded) { @@ -663,6 +692,35 @@ private async Task InstallRust() return exitCode == 0 && exitCodeLatest == 0; } + /// + /// Builds the target arguments to pass to "msrustup toolchain install" from the property. + /// + /// + /// Each target in the semicolon-separated list becomes its own "--target <triple>" argument in the returned string. + /// Returns the empty string when no targets are configured. + /// + private string GetMsRustupTargetArgs() + { + if (string.IsNullOrWhiteSpace(MsRustupTargets)) + { + return string.Empty; + } + + var sb = new System.Text.StringBuilder(); + foreach (var target in MsRustupTargets.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries)) + { + var trimmed = target.Trim(); + if (trimmed.Length == 0) + { + continue; + } + + sb.Append(" --target ").Append(trimmed); + } + + return sb.ToString(); + } + private async Task VerifyInitHashAsync() { using var sha256 = SHA256.Create(); diff --git a/src/Cargo/README.md b/src/Cargo/README.md index e598aec..8b5bdd0 100644 --- a/src/Cargo/README.md +++ b/src/Cargo/README.md @@ -78,8 +78,30 @@ msbuild /t:clearcargocache ### Using MSRustup (Microsoft internal use only) To enable use of MSRustup, you will need to have a rust-toolchain.toml at the root of your repo. The toml file should include a channel specifier that has "ms-" as a prefix, followed by the channel version. ```toml - [toolchain] - channel - ms- + channel = "ms-" ``` - \ No newline at end of file + +#### Optional MSRustup configuration properties + + The SDK exposes a handful of MSBuild properties for advanced scenarios. + +##### `CargoProfile` + +By default the SDK derives the Cargo profile from the MSBuild `Configuration`: `Debug` uses Cargo's default debug profile, and any other configuration is +passed as the `--` value (so `Release` becomes `--release`). + +Set `CargoProfile` to override this and pass `--profile ` to Cargo instead. This is useful when your `Cargo.toml` defines a custom profile +such as `release-windows`. + +##### `MsRustupTargets` + +A semicolon-separated list of target triples to install when running `msrustup toolchain install`. +Each value becomes a `--target ` argument. Use this to enable cross-compilation. + +```xml + + aarch64-pc-windows-msvc;x86_64-pc-windows-msvc + +``` + diff --git a/src/Cargo/sdk/InstallCargo.proj b/src/Cargo/sdk/InstallCargo.proj index 5468001..7cead98 100644 --- a/src/Cargo/sdk/InstallCargo.proj +++ b/src/Cargo/sdk/InstallCargo.proj @@ -4,6 +4,6 @@ - + \ No newline at end of file diff --git a/src/Cargo/sdk/Sdk.props b/src/Cargo/sdk/Sdk.props index 51ea2e6..c586015 100644 --- a/src/Cargo/sdk/Sdk.props +++ b/src/Cargo/sdk/Sdk.props @@ -91,6 +91,18 @@ AzureAuth $(MSBuildProjectDirectory)\bin + + + + diff --git a/src/Cargo/sdk/Sdk.targets b/src/Cargo/sdk/Sdk.targets index e8fc3b7..60702dc 100644 --- a/src/Cargo/sdk/Sdk.targets +++ b/src/Cargo/sdk/Sdk.targets @@ -112,35 +112,35 @@ - + - + - + - + - + - + - +