Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/Cargo.UnitTests/CargoTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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")]
Expand Down Expand Up @@ -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(
Expand Down
76 changes: 67 additions & 9 deletions src/Cargo/CargoTask.cs
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,19 @@ private enum ExitCode
/// </summary>
public string CargoOutputDir { get; set; } = string.Empty;

/// <summary>
/// Gets or sets an optional Cargo profile to pass to cargo as "--profile &lt;value&gt;" for MSRustup.
/// When set, this overrides the behavior of deriving the profile from Configuration.
/// </summary>
public string CargoProfile { get; set; } = string.Empty;

/// <summary>
/// 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 &lt;triple&gt;".
/// Use this to enable cross-compilation.
/// </summary>
public string MsRustupTargets { get; set; } = string.Empty;

/// <inheritdoc/>
public override bool Execute()
{
Expand Down Expand Up @@ -178,7 +191,7 @@ private async Task<bool> ExecuteAsync()

foreach (var registry in GetRegistries(Path.Combine(RepoRoot, _cargoConfigFilePath)))
{
var registryName = registry.Key.Trim().ToUpper();
var registryName = registry.Key.Trim().ToUpper().Replace('-', '_');
Comment thread
wheelv5 marked this conversation as resolved.
_cargoRegistries.Add(registryName);
var tokenName = $"CARGO_REGISTRIES_{registryName}_TOKEN";
AddOrUpdateEnvVar(tokenName, $"Bearer {val}");
Expand Down Expand Up @@ -247,13 +260,7 @@ private async Task<ExitCode> 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;
Expand All @@ -262,6 +269,28 @@ private async Task<ExitCode> CargoRunCommandAsync(string command, string args)
return await ExecuteProcessAsync(_cargoPath, $"{command} {args}", ".", _envVars);
}

/// <summary>
/// For MSRustup, determines the appropriate Cargo profile argument to pass based on the CargoProfile and Configuration properties.
/// </summary>
/// <returns>The Cargo profile argument string, if needed; else an empty string.</returns>
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<bool> DownloadAndInstallRust()
{
try
Expand Down Expand Up @@ -643,7 +672,7 @@ private async Task<bool> 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)
{
Expand All @@ -663,6 +692,35 @@ private async Task<bool> InstallRust()
return exitCode == 0 && exitCodeLatest == 0;
}

/// <summary>
/// Builds the target arguments to pass to "msrustup toolchain install" from the <see cref="MsRustupTargets"/> property.
/// </summary>
/// <returns>
/// Each target in the semicolon-separated list becomes its own "--target &lt;triple&gt;" argument in the returned string.
/// Returns the empty string when no targets are configured.
/// </returns>
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<bool> VerifyInitHashAsync()
{
using var sha256 = SHA256.Create();
Expand Down
28 changes: 25 additions & 3 deletions src/Cargo/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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-<version>
channel = "ms-<version>"
```


#### 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 `--<Configuration>` value (so `Release` becomes `--release`).
Comment thread
wheelv5 marked this conversation as resolved.
Outdated

Set `CargoProfile` to override this and pass `--profile <CargoProfile>` 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 <triple>` argument. Use this to enable cross-compilation.

```xml
<PropertyGroup>
<MsRustupTargets>aarch64-pc-windows-msvc;x86_64-pc-windows-msvc</MsRustupTargets>
</PropertyGroup>
```

2 changes: 1 addition & 1 deletion src/Cargo/sdk/InstallCargo.proj
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@
<UsingTask TaskName="Microsoft.Build.Cargo.CargoTask" AssemblyFile="$(MSBuildThisFileDirectory)..\build\net8.0\Microsoft.Build.Cargo.dll" Condition="'$(MSBuildRuntimeType)' == 'Core'" />
<UsingTask TaskName="Microsoft.Build.Cargo.CargoTask" AssemblyFile="$(MSBuildThisFileDirectory)..\build\net472\Microsoft.Build.Cargo.dll" Condition="'$(MSBuildRuntimeType)' != 'Core'" />
<Target Name="InstallCargo">
<CargoTask EnableAuth="$(AuthMode)" StartupProj="$(MSBuildStartupDirectory)" Command="installcargo" RepoRoot="$(RepoRoot)" CargoInstallationRoot="$(CargoInstallationRoot)" MsRustupAuthType="$(MsRustupAuthType)" CargoOutputDir="$(CargoOutputDir)" />
<CargoTask EnableAuth="$(AuthMode)" StartupProj="$(MSBuildStartupDirectory)" Command="installcargo" RepoRoot="$(RepoRoot)" CargoInstallationRoot="$(CargoInstallationRoot)" MsRustupAuthType="$(MsRustupAuthType)" CargoOutputDir="$(CargoOutputDir)" MsRustupTargets="$(MsRustupTargets)" />
</Target>
</Project>
12 changes: 12 additions & 0 deletions src/Cargo/sdk/Sdk.props
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,18 @@
<CargoInstallationRoot Condition="'$(CargoInstallationRoot)' == ''"></CargoInstallationRoot>
<MsRustupAuthType Condition="'$(MsRustupAuthType)' == ''">AzureAuth</MsRustupAuthType>
<CargoOutputDir Condition="'$(CargoOutputDir)' == ''">$(MSBuildProjectDirectory)\bin</CargoOutputDir>
<!--
Optional Cargo profile override, e.g. "release-windows".
When set, the SDK passes the value as the cargo "profile" argument, instead of deriving the profile from Configuration.
Only applies when the msrustup toolchain is in use.
-->
<CargoProfile Condition="'$(CargoProfile)' == ''"></CargoProfile>
<!--
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 becomes a "&#45;&#45;target <triple>" argument.
Use to enable cross-compilation. Only applies when the msrustup toolchain is in use.
-->
<MsRustupTargets Condition="'$(MsRustupTargets)' == ''"></MsRustupTargets>
</PropertyGroup>
<ItemGroup>
<None Include="**\*.rs" />
Expand Down
16 changes: 8 additions & 8 deletions src/Cargo/sdk/Sdk.targets
Original file line number Diff line number Diff line change
Expand Up @@ -112,35 +112,35 @@
<MSBuild
Projects="$(MSBuildThisFileDirectory)InstallCargo.proj"
Targets="InstallCargo"
Properties="EnableTelemetryLoggerCopy=$(EnableTelemetryLoggerCopy);TelemetryLoggerLocation=$(TelemetryLoggerLocation);TelemetryLoggerSourcePath=$(TelemetryLoggerSourcePath);TelemetryLoggerInstallId=$(TelemetryLoggerInstallId);RepoRoot=$(RepoRoot);CargoInstallationRoot=$(CargoInstallationRoot);MsRustupAuthType=$(MsRustupAuthType);CargoOutputDir=$(CargoOutputDir)"
Properties="EnableTelemetryLoggerCopy=$(EnableTelemetryLoggerCopy);TelemetryLoggerLocation=$(TelemetryLoggerLocation);TelemetryLoggerSourcePath=$(TelemetryLoggerSourcePath);TelemetryLoggerInstallId=$(TelemetryLoggerInstallId);RepoRoot=$(RepoRoot);CargoInstallationRoot=$(CargoInstallationRoot);MsRustupAuthType=$(MsRustupAuthType);CargoOutputDir=$(CargoOutputDir);MsRustupTargets=$(MsRustupTargets)"
RemoveProperties="NuGetInteractive;MSBuildRestoreSessionId;TargetFramework;RuntimeIdentifier" />
</Target>
<Target Name="CargoFetch" AfterTargets="InstallCargo">
<CargoTask EnableAuth="$(AuthMode)" StartupProj="$(StartupProj)" Command="fetch" RepoRoot="$(RepoRoot)" CargoInstallationRoot="$(CargoInstallationRoot)" MsRustupAuthType="$(MsRustupAuthType)" CargoOutputDir="$(CargoOutputDir)" />
</Target>
<Target Name="CargoBuild" AfterTargets="CoreCompile">
<CargoTask EnableAuth="$(AuthMode)" StartupProj="$(StartupProj)" Command="build" CommandArgs="$(CargoBuildCommandArgs)" Configuration="$(Configuration)" RepoRoot="$(RepoRoot)" CargoInstallationRoot="$(CargoInstallationRoot)" MsRustupAuthType="$(MsRustupAuthType)" CargoOutputDir="$(CargoOutputDir)" />
<CargoTask EnableAuth="$(AuthMode)" StartupProj="$(StartupProj)" Command="build" CommandArgs="$(CargoBuildCommandArgs)" Configuration="$(Configuration)" RepoRoot="$(RepoRoot)" CargoInstallationRoot="$(CargoInstallationRoot)" MsRustupAuthType="$(MsRustupAuthType)" CargoOutputDir="$(CargoOutputDir)" CargoProfile="$(CargoProfile)" />
</Target>
<Target Name="CargoTest" DependsOnTargets="CargoFetch">
<CargoTask StartupProj="$(StartupProj)" Command="test" CommandArgs="$(CargoTestCommandArgs)" CargoInstallationRoot="$(CargoInstallationRoot)" MsRustupAuthType="$(MsRustupAuthType)" CargoOutputDir="$(CargoOutputDir)" />
<CargoTask StartupProj="$(StartupProj)" Command="test" CommandArgs="$(CargoTestCommandArgs)" CargoInstallationRoot="$(CargoInstallationRoot)" MsRustupAuthType="$(MsRustupAuthType)" CargoOutputDir="$(CargoOutputDir)" CargoProfile="$(CargoProfile)" />
</Target>
<Target Name="CargoRun" DependsOnTargets="CargoFetch">
<CargoTask StartupProj="$(StartupProj)" Command="run" CommandArgs="$(CargoRunCommandArgs)" CargoInstallationRoot="$(CargoInstallationRoot)" MsRustupAuthType="$(MsRustupAuthType)" CargoOutputDir="$(CargoOutputDir)" />
<CargoTask StartupProj="$(StartupProj)" Command="run" CommandArgs="$(CargoRunCommandArgs)" CargoInstallationRoot="$(CargoInstallationRoot)" MsRustupAuthType="$(MsRustupAuthType)" CargoOutputDir="$(CargoOutputDir)" CargoProfile="$(CargoProfile)" />
</Target>
<Target Name="CargoDoc" DependsOnTargets="CargoFetch">
<CargoTask StartupProj="$(StartupProj)" Command="doc" CommandArgs="$(CargoDocCommandArgs)" CargoInstallationRoot="$(CargoInstallationRoot)" MsRustupAuthType="$(MsRustupAuthType)" CargoOutputDir="$(CargoOutputDir)" />
<CargoTask StartupProj="$(StartupProj)" Command="doc" CommandArgs="$(CargoDocCommandArgs)" CargoInstallationRoot="$(CargoInstallationRoot)" MsRustupAuthType="$(MsRustupAuthType)" CargoOutputDir="$(CargoOutputDir)" CargoProfile="$(CargoProfile)" />
</Target>
<Target Name="CargoUpdate" DependsOnTargets="CargoFetch">
<CargoTask StartupProj="$(StartupProj)" Command="update" CommandArgs="$(CargoUpdateCommandArgs)" CargoInstallationRoot="$(CargoInstallationRoot)" MsRustupAuthType="$(MsRustupAuthType)" CargoOutputDir="$(CargoOutputDir)" />
</Target>
<Target Name="CargoInstall" DependsOnTargets="CargoFetch">
<CargoTask StartupProj="$(StartupProj)" Command="install" CommandArgs="$(CargoInstallCommandArgs)" CargoInstallationRoot="$(CargoInstallationRoot)" MsRustupAuthType="$(MsRustupAuthType)" CargoOutputDir="$(CargoOutputDir)" />
<CargoTask StartupProj="$(StartupProj)" Command="install" CommandArgs="$(CargoInstallCommandArgs)" CargoInstallationRoot="$(CargoInstallationRoot)" MsRustupAuthType="$(MsRustupAuthType)" CargoOutputDir="$(CargoOutputDir)" CargoProfile="$(CargoProfile)" />
</Target>
<Target Name="CargoCommand" DependsOnTargets="CargoFetch">
<CargoTask StartupProj="$(StartupProj)" Command="$(CargoCommand)" CommandArgs="$(CargoCommandArgs)" CargoInstallationRoot="$(CargoInstallationRoot)" MsRustupAuthType="$(MsRustupAuthType)" CargoOutputDir="$(CargoOutputDir)" />
<CargoTask StartupProj="$(StartupProj)" Command="$(CargoCommand)" CommandArgs="$(CargoCommandArgs)" CargoInstallationRoot="$(CargoInstallationRoot)" MsRustupAuthType="$(MsRustupAuthType)" CargoOutputDir="$(CargoOutputDir)" CargoProfile="$(CargoProfile)" />
</Target>
<Target Name="CargoClean">
<CargoTask StartupProj="$(StartupProj)" Command="clean" CommandArgs="$(CargoCleanCommandArgs)" CargoInstallationRoot="$(CargoInstallationRoot)" MsRustupAuthType="$(MsRustupAuthType)" CargoOutputDir="$(CargoOutputDir)" />
<CargoTask StartupProj="$(StartupProj)" Command="clean" CommandArgs="$(CargoCleanCommandArgs)" CargoInstallationRoot="$(CargoInstallationRoot)" MsRustupAuthType="$(MsRustupAuthType)" CargoOutputDir="$(CargoOutputDir)" CargoProfile="$(CargoProfile)" />
</Target>
<Target Name="ClearCargoCache">
<CargoTask StartupProj="$(StartupProj)" Command="clearcargocache" CommandArgs="$(ClearCargoCacheCommandArgs)" CargoInstallationRoot="$(CargoInstallationRoot)" MsRustupAuthType="$(MsRustupAuthType)" CargoOutputDir="$(CargoOutputDir)" />
Expand Down