Skip to content

Commit c6ad8f5

Browse files
committed
Add support for Windows x64 and arm64 builds
Previously, GCM was only built for x86 on Windows. This commit adds support for building for and on Windows x64 and arm64. It builds the host architecture by default and supports explicitly specifying the target architecture. Signed-off-by: Dennis Ameling <dennis@dennisameling.com>
1 parent a68abef commit c6ad8f5

File tree

6 files changed

+148
-36
lines changed

6 files changed

+148
-36
lines changed

.azure-pipelines/release.yml

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,24 @@ parameters:
3131
- name: windows_matrix
3232
type: object
3333
default:
34-
- id: windows_x64
34+
- id: windows_x86
3535
jobName: 'Windows (x86)'
3636
runtime: win-x86
3737
pool: GitClientPME-1ESHostedPool-intel-pc
3838
image: win-x86_64-ado1es
3939
os: windows
40+
- id: windows_x64
41+
jobName: 'Windows (x64)'
42+
runtime: win-x64
43+
pool: GitClientPME-1ESHostedPool-intel-pc
44+
image: win-x86_64-ado1es
45+
os: windows
46+
- id: windows_arm64
47+
jobName: 'Windows (ARM64)'
48+
runtime: win-arm64
49+
pool: GitClientPME-1ESHostedPool-intel-pc
50+
image: win-x86_64-ado1es
51+
os: windows
4052

4153
- name: macos_matrix
4254
type: object
@@ -136,14 +148,15 @@ extends:
136148
arguments: |
137149
-Configuration Release `
138150
-Output $(Build.ArtifactStagingDirectory)\payload `
139-
-SymbolOutput $(Build.ArtifactStagingDirectory)\symbols_raw
151+
-SymbolOutput $(Build.ArtifactStagingDirectory)\symbols_raw `
152+
-RuntimeIdentifier ${{ dim.runtime }}
140153
- task: ArchiveFiles@2
141154
displayName: 'Archive symbols'
142155
inputs:
143156
rootFolderOrFile: '$(Build.ArtifactStagingDirectory)\symbols_raw'
144157
includeRootFolder: false
145158
archiveType: zip
146-
archiveFile: '$(Build.ArtifactStagingDirectory)\symbols\gcm-win-x86-$(version)-symbols.zip'
159+
archiveFile: '$(Build.ArtifactStagingDirectory)\symbols\gcm-${{ dim.runtime }}-$(version)-symbols.zip'
147160
- task: EsrpCodeSigning@5
148161
condition: and(succeeded(), eq('${{ parameters.esrp }}', true))
149162
displayName: 'Sign payload'
@@ -195,6 +208,7 @@ extends:
195208
-p:NoLayout=true `
196209
-p:PayloadPath="$(Build.ArtifactStagingDirectory)\payload" `
197210
-p:OutputPath="$(Build.ArtifactStagingDirectory)\installers"
211+
-p:RuntimeIdentifier="${{ dim.runtime }}"
198212
- task: EsrpCodeSigning@5
199213
condition: and(succeeded(), eq('${{ parameters.esrp }}', true))
200214
displayName: 'Sign installers'
@@ -239,7 +253,7 @@ extends:
239253
rootFolderOrFile: '$(Build.ArtifactStagingDirectory)\payload'
240254
includeRootFolder: false
241255
archiveType: zip
242-
archiveFile: '$(Build.ArtifactStagingDirectory)\installers\gcm-win-x86-$(version).zip'
256+
archiveFile: '$(Build.ArtifactStagingDirectory)\installers\gcm-${{ dim.runtime }}-$(version).zip'
243257
- task: PowerShell@2
244258
displayName: 'Collect artifacts for publishing'
245259
inputs:
@@ -774,6 +788,12 @@ extends:
774788
- input: pipelineArtifact
775789
artifactName: 'win-x86'
776790
targetPath: $(Pipeline.Workspace)/assets/win-x86
791+
- input: pipelineArtifact
792+
artifactName: 'win-x64'
793+
targetPath: $(Pipeline.Workspace)/assets/win-x64
794+
- input: pipelineArtifact
795+
artifactName: 'win-arm64'
796+
targetPath: $(Pipeline.Workspace)/assets/win-arm64
777797
- input: pipelineArtifact
778798
artifactName: 'osx-x64'
779799
targetPath: $(Pipeline.Workspace)/assets/osx-x64
@@ -805,6 +825,10 @@ extends:
805825
assets: |
806826
$(Pipeline.Workspace)/assets/win-x86/*.exe
807827
$(Pipeline.Workspace)/assets/win-x86/*.zip
828+
$(Pipeline.Workspace)/assets/win-x64/*.exe
829+
$(Pipeline.Workspace)/assets/win-x64/*.zip
830+
$(Pipeline.Workspace)/assets/win-arm64/*.exe
831+
$(Pipeline.Workspace)/assets/win-arm64/*.zip
808832
$(Pipeline.Workspace)/assets/osx-x64/*.pkg
809833
$(Pipeline.Workspace)/assets/osx-x64/*.tar.gz
810834
$(Pipeline.Workspace)/assets/osx-arm64/*.pkg

.github/workflows/continuous-integration.yml

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,16 @@ jobs:
1313
# ================================
1414
windows:
1515
name: Windows
16-
runs-on: windows-latest
16+
runs-on: ${{ matrix.os }}
17+
strategy:
18+
matrix:
19+
include:
20+
- runtime: win-x86
21+
os: windows-latest
22+
- runtime: win-x64
23+
os: windows-latest
24+
- runtime: win-arm64
25+
os: windows-11-arm
1726

1827
steps:
1928
- uses: actions/checkout@v6
@@ -27,24 +36,29 @@ jobs:
2736
run: dotnet restore
2837

2938
- name: Build
30-
run: dotnet build --configuration WindowsRelease
39+
run: |
40+
dotnet build src/windows/Installer.Windows/Installer.Windows.csproj `
41+
--configuration=Release `
42+
--runtime=${{ matrix.runtime }}
3143
3244
- name: Test
3345
run: |
34-
dotnet test --verbosity normal --configuration=WindowsRelease
46+
dotnet test --verbosity normal `
47+
--configuration=WindowsRelease `
48+
--runtime=${{ matrix.runtime }}
3549
3650
- name: Prepare artifacts
3751
shell: bash
3852
run: |
3953
mkdir -p artifacts/bin
40-
mv out/windows/Installer.Windows/bin/Release/net472/win-x86 artifacts/bin/
41-
cp out/windows/Installer.Windows/bin/Release/net472/win-x86.sym/* artifacts/bin/win-x86/
42-
mv out/windows/Installer.Windows/bin/Release/net472/gcm*.exe artifacts/
54+
mv out/windows/Installer.Windows/bin/Release/net472/${{ matrix.runtime }}/gcm*.exe artifacts/
55+
mv out/windows/Installer.Windows/bin/Release/net472/${{ matrix.runtime }} artifacts/bin/
56+
cp out/windows/Installer.Windows/bin/Release/net472/${{ matrix.runtime }}.sym/* artifacts/bin/${{ matrix.runtime }}/
4357
4458
- name: Upload artifacts
4559
uses: actions/upload-artifact@v6
4660
with:
47-
name: win-x86
61+
name: ${{ matrix.runtime }}
4862
path: |
4963
artifacts
5064

src/shared/Git-Credential-Manager/Git-Credential-Manager.csproj

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
1-
<Project Sdk="Microsoft.NET.Sdk">
1+
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
44
<OutputType>Exe</OutputType>
55
<TargetFrameworks>net8.0</TargetFrameworks>
66
<TargetFrameworks Condition="'$(OSPlatform)'=='windows'">net472;net8.0</TargetFrameworks>
7-
<RuntimeIdentifiers>win-x86;osx-x64;linux-x64;osx-arm64;linux-arm64;linux-arm</RuntimeIdentifiers>
8-
<PlatformTarget Condition="'$(OSPlatform)'=='windows'">x86</PlatformTarget>
7+
<RuntimeIdentifiers>win-x86;win-x64;win-arm64;osx-x64;linux-x64;osx-arm64;linux-arm64;linux-arm</RuntimeIdentifiers>
98
<AssemblyName>git-credential-manager</AssemblyName>
109
<RootNamespace>GitCredentialManager</RootNamespace>
1110
<ApplicationIcon>$(RepoAssetsPath)gcmicon.ico</ApplicationIcon>

src/windows/Installer.Windows/Installer.Windows.csproj

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,19 @@
1-
<Project>
1+
<Project>
22
<!-- Implicit SDK props import -->
33
<Import Project="Sdk.props" Sdk="Microsoft.NET.Sdk" />
44

5+
<!-- Default RuntimeIdentifier to the host architecture if not specified -->
6+
<PropertyGroup Condition="'$(RuntimeIdentifier)' == ''">
7+
<RuntimeIdentifier Condition="'$([System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture)' == 'X64'">win-x64</RuntimeIdentifier>
8+
<RuntimeIdentifier Condition="'$([System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture)' == 'X86'">win-x86</RuntimeIdentifier>
9+
<RuntimeIdentifier Condition="'$([System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture)' == 'Arm64'">win-arm64</RuntimeIdentifier>
10+
</PropertyGroup>
11+
512
<PropertyGroup>
613
<TargetFramework>net472</TargetFramework>
714
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
815
<EnableDefaultItems>false</EnableDefaultItems>
9-
<PayloadPath>$(PlatformOutPath)Installer.Windows\bin\$(Configuration)\net472\win-x86</PayloadPath>
16+
<PayloadPath>$(PlatformOutPath)Installer.Windows\bin\$(Configuration)\net472\$(RuntimeIdentifier)</PayloadPath>
1017
<InnoSetupVersion>6.3.1</InnoSetupVersion>
1118
</PropertyGroup>
1219

@@ -27,12 +34,20 @@
2734

2835
<Target Name="CoreCompile" Condition="'$(OSPlatform)'=='windows'">
2936
<PropertyGroup>
30-
<InnoSetupCommandSystem>"$(NuGetPackageRoot)Tools.InnoSetup\$(InnoSetupVersion)\tools\ISCC.exe" /DPayloadDir="$(PayloadPath)" /DInstallTarget=system "$(RepoSrcPath)\windows\Installer.Windows\Setup.iss" /O"$(OutputPath)"</InnoSetupCommandSystem>
31-
<InnoSetupCommandUser>"$(NuGetPackageRoot)Tools.InnoSetup\$(InnoSetupVersion)\tools\ISCC.exe" /DPayloadDir="$(PayloadPath)" /DInstallTarget=user "$(RepoSrcPath)\windows\Installer.Windows\Setup.iss" /O"$(OutputPath)"</InnoSetupCommandUser>
37+
<InnoSetupCommandSystem>"$(NuGetPackageRoot)Tools.InnoSetup\$(InnoSetupVersion)\tools\ISCC.exe" /DPayloadDir="$(PayloadPath)" /DInstallTarget=system /DGcmRuntimeIdentifier="$(RuntimeIdentifier)" "$(RepoSrcPath)\windows\Installer.Windows\Setup.iss" /O"$(OutputPath)"</InnoSetupCommandSystem>
38+
<InnoSetupCommandUser>"$(NuGetPackageRoot)Tools.InnoSetup\$(InnoSetupVersion)\tools\ISCC.exe" /DPayloadDir="$(PayloadPath)" /DInstallTarget=user /DGcmRuntimeIdentifier="$(RuntimeIdentifier)" "$(RepoSrcPath)\windows\Installer.Windows\Setup.iss" /O"$(OutputPath)"</InnoSetupCommandUser>
3239
</PropertyGroup>
3340

3441
<Message Text="Lay Out" Importance="High" />
35-
<Exec Condition="'$(NoLayout)'!='true'" Command="powershell.exe –NonInteractive –ExecutionPolicy Unrestricted -Command &quot;&amp; {&amp;'$(MSBuildProjectDirectory)\layout.ps1' -Configuration '$(Configuration)' -Output '$(PayloadPath)'}&quot;" />
42+
<Exec Condition="'$(NoLayout)'!='true'"
43+
ConsoleToMSBuild="true"
44+
Command="powershell.exe –NonInteractive –ExecutionPolicy Unrestricted -Command &quot;&amp; {&amp;'$(MSBuildProjectDirectory)\layout.ps1' -Configuration '$(Configuration)' -Output '$(PayloadPath)' -RuntimeIdentifier '$(RuntimeIdentifier)'; if ($?) { exit 0 } else { exit 1 }}&quot;"
45+
IgnoreExitCode="true">
46+
<!-- If we want to display the console output if the exit code is not 0, we need to capture it and then output it using the <Error /> below -->
47+
<Output TaskParameter="ExitCode" PropertyName="ExitCodeOfExec" />
48+
<Output TaskParameter="ConsoleOutput" PropertyName="OutputOfExec" />
49+
</Exec>
50+
<Error Condition="'$(NoLayout)'!='true' AND '$(ExitCodeOfExec)' != '0'" Text="Layout script failed with exit code $(ExitCodeOfExec) and message $(OutputOfExec)" />
3651
<Message Text="$(InnoSetupCommandSystem)" Importance="High" />
3752
<Exec Command="$(InnoSetupCommandSystem)" />
3853
<Message Text="$(InnoSetupCommandUser)" Importance="High" />

src/windows/Installer.Windows/Setup.iss

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@
1515
#error Installer target property 'InstallTarget' must be specifed
1616
#endif
1717

18+
#ifndef GcmRuntimeIdentifier
19+
#error GCM Runtime Identifier 'GcmRuntimeIdentifier' must be specifed (e.g. win-x64)
20+
#endif
21+
1822
#if InstallTarget == "user"
1923
#define GcmAppId "{{aa76d31d-432c-42ee-844c-bc0bc801cef3}}"
2024
#define GcmLongName "Git Credential Manager (User)"
@@ -40,7 +44,6 @@
4044
#define GcmRepoRoot "..\..\.."
4145
#define GcmAssets GcmRepoRoot + "\assets"
4246
#define GcmExe "git-credential-manager.exe"
43-
#define GcmArch "x86"
4447

4548
#ifnexist PayloadDir + "\" + GcmExe
4649
#error Payload files are missing
@@ -67,9 +70,17 @@ AppUpdatesURL={#GcmUrl}
6770
AppContact={#GcmUrl}
6871
AppCopyright={#GcmCopyright}
6972
AppReadmeFile={#GcmReadme}
73+
; Windows ARM64 supports installing and running x64 binaries, but not vice versa.
74+
#if GcmRuntimeIdentifier=="win-x64"
75+
ArchitecturesAllowed=x64compatible
76+
ArchitecturesInstallIn64BitMode=x64compatible
77+
#elif GcmRuntimeIdentifier=="win-arm64"
78+
ArchitecturesAllowed=arm64
79+
ArchitecturesInstallIn64BitMode=arm64
80+
#endif
7081
VersionInfoVersion={#GcmVersion}
7182
LicenseFile={#GcmRepoRoot}\LICENSE
72-
OutputBaseFilename={#GcmSetupExe}-win-{#GcmArch}-{#GcmVersionSimple}
83+
OutputBaseFilename={#GcmSetupExe}-{#GcmRuntimeIdentifier}-{#GcmVersionSimple}
7384
DefaultDirName={autopf}\{#GcmShortName}
7485
Compression=lzma2
7586
SolidCompression=yes

src/windows/Installer.Windows/layout.ps1

Lines changed: 64 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,29 @@
11
# Inputs
2-
param ([Parameter(Mandatory)] $Configuration, [Parameter(Mandatory)] $Output, $SymbolOutput)
2+
param ([Parameter(Mandatory)] $Configuration, [Parameter(Mandatory)] $Output, $RuntimeIdentifier, $SymbolOutput)
33

44
Write-Output "Output: $Output"
55

6+
# Determine a runtime if one was not provided
7+
if (-not $RuntimeIdentifier) {
8+
$arch = $env:PROCESSOR_ARCHITECTURE
9+
switch ($arch) {
10+
"AMD64" { $RuntimeIdentifier = "win-x64" }
11+
"x86" { $RuntimeIdentifier = "win-x86" }
12+
"ARM64" { $RuntimeIdentifier = "win-arm64" }
13+
default {
14+
Write-Host "Unknown architecture: $arch"
15+
exit 1
16+
}
17+
}
18+
}
19+
20+
Write-Output "Building for runtime '$RuntimeIdentifier'"
21+
22+
if ($RuntimeIdentifier -ne 'win-x86' -and $RuntimeIdentifier -ne 'win-x64' -and $RuntimeIdentifier -ne 'win-arm64') {
23+
Write-Host "Unsupported RuntimeIdentifier: $RuntimeIdentifier"
24+
exit 1
25+
}
26+
627
# Directories
728
$THISDIR = $PSScriptRoot
829
$ROOT = (Get-Item $THISDIR).Parent.Parent.Parent.FullName
@@ -41,27 +62,55 @@ Write-Output "Publishing core application..."
4162
dotnet publish "$GCM_SRC" `
4263
--framework net472 `
4364
--configuration "$Configuration" `
44-
--runtime win-x86 `
65+
--runtime $RuntimeIdentifier `
4566
--output "$PAYLOAD"
4667

4768
# Delete libraries that are not needed for Windows but find their way
4869
# into the publish output.
4970
Remove-Item -Path "$PAYLOAD/*.dylib" -Force -ErrorAction Ignore
5071

51-
# Delete extraneous files that get included for other architectures
52-
# We only care about x86 as the core GCM executable is only targeting x86
53-
Remove-Item -Path "$PAYLOAD/arm/" -Recurse -Force -ErrorAction Ignore
54-
Remove-Item -Path "$PAYLOAD/arm64/" -Recurse -Force -ErrorAction Ignore
55-
Remove-Item -Path "$PAYLOAD/x64/" -Recurse -Force -ErrorAction Ignore
72+
# Delete extraneous files that get included for other runtimes
5673
Remove-Item -Path "$PAYLOAD/musl-x64/" -Recurse -Force -ErrorAction Ignore
57-
Remove-Item -Path "$PAYLOAD/runtimes/win-arm64/" -Recurse -Force -ErrorAction Ignore
58-
Remove-Item -Path "$PAYLOAD/runtimes/win-x64/" -Recurse -Force -ErrorAction Ignore
59-
60-
# The Avalonia and MSAL binaries in these directories are already included in
61-
# the $PAYLOAD directory directly, so we can delete these extra copies.
62-
Remove-Item -Path "$PAYLOAD/x86/libSkiaSharp.dll" -Recurse -Force -ErrorAction Ignore
63-
Remove-Item -Path "$PAYLOAD/x86/libHarfBuzzSharp.dll" -Recurse -Force -ErrorAction Ignore
64-
Remove-Item -Path "$PAYLOAD/runtimes/win-x86/native/msalruntime_x86.dll" -Recurse -Force -ErrorAction Ignore
74+
75+
switch ($RuntimeIdentifier) {
76+
"win-x86" {
77+
Remove-Item -Path "$PAYLOAD/arm/" -Recurse -Force -ErrorAction Ignore
78+
Remove-Item -Path "$PAYLOAD/arm64/" -Recurse -Force -ErrorAction Ignore
79+
Remove-Item -Path "$PAYLOAD/x64/" -Recurse -Force -ErrorAction Ignore
80+
Remove-Item -Path "$PAYLOAD/runtimes/win-arm64/" -Recurse -Force -ErrorAction Ignore
81+
Remove-Item -Path "$PAYLOAD/runtimes/win-x64/" -Recurse -Force -ErrorAction Ignore
82+
# The Avalonia and MSAL binaries are already included in the $PAYLOAD directory directly
83+
Remove-Item -Path "$PAYLOAD/x86/libSkiaSharp.dll" -Force -ErrorAction Ignore
84+
Remove-Item -Path "$PAYLOAD/x86/libHarfBuzzSharp.dll" -Force -ErrorAction Ignore
85+
Remove-Item -Path "$PAYLOAD/runtimes/win-x86/native/msalruntime_x86.dll" -Force -ErrorAction Ignore
86+
}
87+
"win-x64" {
88+
Remove-Item -Path "$PAYLOAD/arm/" -Recurse -Force -ErrorAction Ignore
89+
Remove-Item -Path "$PAYLOAD/arm64/" -Recurse -Force -ErrorAction Ignore
90+
Remove-Item -Path "$PAYLOAD/x86/" -Recurse -Force -ErrorAction Ignore
91+
Remove-Item -Path "$PAYLOAD/runtimes/win-arm64/" -Recurse -Force -ErrorAction Ignore
92+
Remove-Item -Path "$PAYLOAD/runtimes/win-x86/" -Recurse -Force -ErrorAction Ignore
93+
# The Avalonia and MSAL binaries are already included in the $PAYLOAD directory directly
94+
Remove-Item -Path "$PAYLOAD/x64/libSkiaSharp.dll" -Force -ErrorAction Ignore
95+
Remove-Item -Path "$PAYLOAD/x64/libHarfBuzzSharp.dll" -Force -ErrorAction Ignore
96+
Remove-Item -Path "$PAYLOAD/x64/libSkiaSharp.so" -Force -ErrorAction Ignore
97+
Remove-Item -Path "$PAYLOAD/x64/libHarfBuzzSharp.so" -Force -ErrorAction Ignore
98+
Remove-Item -Path "$PAYLOAD/runtimes/win-x64/native/msalruntime.dll" -Force -ErrorAction Ignore
99+
}
100+
"win-arm64" {
101+
Remove-Item -Path "$PAYLOAD/arm/" -Recurse -Force -ErrorAction Ignore
102+
Remove-Item -Path "$PAYLOAD/x86/" -Recurse -Force -ErrorAction Ignore
103+
Remove-Item -Path "$PAYLOAD/x64/" -Recurse -Force -ErrorAction Ignore
104+
Remove-Item -Path "$PAYLOAD/runtimes/win-x86/" -Recurse -Force -ErrorAction Ignore
105+
Remove-Item -Path "$PAYLOAD/runtimes/win-x64/" -Recurse -Force -ErrorAction Ignore
106+
# The Avalonia and MSAL binaries are already included in the $PAYLOAD directory directly
107+
Remove-Item -Path "$PAYLOAD/arm64/libSkiaSharp.dll" -Force -ErrorAction Ignore
108+
Remove-Item -Path "$PAYLOAD/arm64/libHarfBuzzSharp.dll" -Force -ErrorAction Ignore
109+
Remove-Item -Path "$PAYLOAD/arm64/libSkiaSharp.so" -Force -ErrorAction Ignore
110+
Remove-Item -Path "$PAYLOAD/arm64/libHarfBuzzSharp.so" -Force -ErrorAction Ignore
111+
Remove-Item -Path "$PAYLOAD/runtimes/win-arm64/native/msalruntime_arm64.dll" -Force -ErrorAction Ignore
112+
}
113+
}
65114

66115
# Delete localized resource assemblies - we don't localize the core GCM assembly anyway
67116
Get-ChildItem "$PAYLOAD" -Recurse -Include "*.resources.dll" | Remove-Item -Force -ErrorAction Ignore

0 commit comments

Comments
 (0)