Skip to content

Commit 8f25747

Browse files
committed
Statically link libgit2 into NativeAOT executables via vcpkg
Replace the LibGit2Sharp.NativeBinaries NuGet package (which shipped a dynamic git2-*.dll) with a vcpkg-built static git2.lib that the NativeAOT linker embeds directly into the executable. This eliminates libgit2 DLL-missing crashes we see in telemetry. A side benefit of this approach is that we can apply patches to libgit2 that haven't been included in an official release yet, via the vcpkg overlay port in overlays/libgit2/. How it works: - vcpkg manifest (vcpkg.json) declares libgit2 as a dependency - Custom triplet (x64-windows-static-aot) builds with static CRT and library linkage, producing git2.lib instead of git2.dll - Overlay port (overlays/libgit2/) pins libgit2 v1.9.3 and can carry patches ahead of upstream releases - Directory.Build.props wires <DirectPInvoke> and <NativeLibrary> items so the NativeAOT linker resolves P/Invoke calls at link time and embeds git2 + transitive deps (pcre, zlib, http-parser) To rebuild vcpkg libs locally: vcpkg install --triplet x64-windows-static-aot \ --overlay-triplets=triplets --overlay-ports=overlays Changes: - Directory.Build.props: DirectPInvoke + NativeLibrary for AOT link, unconditional libgit2_filename=git2 (was git2-a418d9d from NuGet) - Directory.Packages.props: remove LibGit2Sharp.NativeBinaries - GVFS.Common.csproj, GVFS.Hooks.csproj: remove NuGet package ref - Readme.md: reference THIRD-PARTY-NOTICES.md from license section - THIRD-PARTY-NOTICES.md: document libgit2 (GPLv2 + linking exception), SQLite (public domain), SQLitePCLRaw (Apache 2.0) - vcpkg.json, vcpkg-configuration.json: vcpkg manifest + baseline - triplets/x64-windows-static-aot.cmake: static linkage triplet - overlays/libgit2/: port overlay (v1.9.3) from devprod.razzletools - .gitignore: exclude vcpkg_installed/ License: libgit2's COPYING includes an explicit linking exception that permits static linking without imposing GPL on the consuming program. Assisted-by: Claude Opus 4.6 Signed-off-by: Tyrie Vella <tyrielv@gmail.com>
1 parent be1ef98 commit 8f25747

16 files changed

Lines changed: 446 additions & 7 deletions

.github/workflows/build.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,13 @@ jobs:
204204
if: steps.skip.outputs.result != 'true'
205205
uses: microsoft/setup-msbuild@v3.0.0
206206

207+
- name: Install vcpkg native dependencies
208+
if: steps.skip.outputs.result != 'true'
209+
shell: cmd
210+
run: |
211+
"%VCPKG_INSTALLATION_ROOT%\vcpkg.exe" install --triplet x64-windows-static-aot --overlay-triplets=src\triplets --overlay-ports=src\overlays --x-install-root=src\vcpkg_installed\static --x-manifest-root=src || exit /b 1
212+
"%VCPKG_INSTALLATION_ROOT%\vcpkg.exe" install --triplet x64-windows-dynamic --overlay-triplets=src\triplets --overlay-ports=src\overlays --x-install-root=src\vcpkg_installed\dynamic --x-manifest-root=src || exit /b 1
213+
207214
- name: Build VFS for Git
208215
if: steps.skip.outputs.result != 'true'
209216
shell: cmd

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -228,4 +228,6 @@ ModelManifest.xml
228228
.vscode/
229229

230230
# ProjFS Kext Unit Test coverage results
231-
ProjFS.Mac/CoverageResult.txt
231+
ProjFS.Mac/CoverageResult.txt
232+
# vcpkg build output (rebuilt locally via vcpkg install)
233+
vcpkg_installed/

Directory.Build.props

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,74 @@
3333
<BaseIntermediateOutputPath>$(ProjectOutPath)obj\</BaseIntermediateOutputPath>
3434
</PropertyGroup>
3535

36+
<!--
37+
Static native linking: embed libgit2 directly into AOT-compiled executables.
38+
39+
vcpkg builds a static git2.lib (via the x64-windows-static-aot triplet) which
40+
the NativeAOT linker links into the final executable. This eliminates the
41+
"DLL missing" crash vector for libgit2.
42+
43+
How it works:
44+
1. vcpkg install produces git2.lib + transitive deps (pcre, zlib, etc.)
45+
2. <NativeLibrary> items tell the NativeAOT linker where to find the .lib files
46+
3. <DirectPInvoke> tells the linker to resolve P/Invoke calls at link time
47+
4. libgit2_filename is overridden from "git2-XXXXXXX" (NuGet) to "git2" (vcpkg)
48+
49+
A side benefit of this approach: we can apply patches to libgit2 that haven't
50+
been included in an official release yet, via the overlay port in overlays/.
51+
52+
To rebuild vcpkg libs after overlay changes:
53+
vcpkg install [triplet x64-windows-static-aot] [overlay-triplets=triplets] [overlay-ports=overlays]
54+
55+
See THIRD-PARTY-NOTICES.md for license details on these native libraries.
56+
-->
57+
<PropertyGroup Condition="'$(PublishAot)' == 'true'">
58+
<VcpkgInstalledDir>$(RepoSrcPath)vcpkg_installed\static\x64-windows-static-aot\</VcpkgInstalledDir>
59+
</PropertyGroup>
60+
61+
<!-- Set libgit2 library name unconditionally — all builds use vcpkg-sourced libgit2 -->
62+
<PropertyGroup Condition="'$(MSBuildProjectExtension)' == '.csproj'">
63+
<libgit2_filename>git2</libgit2_filename>
64+
</PropertyGroup>
65+
66+
<ItemGroup Condition="'$(PublishAot)' == 'true'">
67+
<DirectPInvoke Include="git2" />
68+
69+
<!-- libgit2 static library and its transitive dependencies -->
70+
<NativeLibrary Include="$(VcpkgInstalledDir)lib\git2.lib" />
71+
<NativeLibrary Include="$(VcpkgInstalledDir)lib\pcre.lib" />
72+
<NativeLibrary Include="$(VcpkgInstalledDir)lib\http_parser.lib" />
73+
<NativeLibrary Include="$(VcpkgInstalledDir)lib\zs.lib" />
74+
75+
<!-- Windows system libraries required by libgit2 (WinHTTP TLS backend) -->
76+
<NativeLibrary Include="winhttp.lib" />
77+
<NativeLibrary Include="crypt32.lib" />
78+
<NativeLibrary Include="rpcrt4.lib" />
79+
<NativeLibrary Include="secur32.lib" />
80+
</ItemGroup>
81+
82+
<!--
83+
Non-AOT projects (tests) need git2.dll for runtime P/Invoke.
84+
Copy from the vcpkg dynamic build output.
85+
-->
86+
<ItemGroup Condition="'$(PublishAot)' != 'true' and '$(MSBuildProjectExtension)' == '.csproj'">
87+
<Content Include="$(RepoSrcPath)vcpkg_installed\dynamic\x64-windows-dynamic\bin\git2.dll">
88+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
89+
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
90+
<Link>git2.dll</Link>
91+
</Content>
92+
<Content Include="$(RepoSrcPath)vcpkg_installed\dynamic\x64-windows-dynamic\bin\pcre.dll">
93+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
94+
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
95+
<Link>pcre.dll</Link>
96+
</Content>
97+
<Content Include="$(RepoSrcPath)vcpkg_installed\dynamic\x64-windows-dynamic\bin\z.dll">
98+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
99+
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
100+
<Link>z.dll</Link>
101+
</Content>
102+
</ItemGroup>
103+
36104
<!-- Native project properties -->
37105
<PropertyGroup Condition="'$(MSBuildProjectExtension)' == '.vcxproj'">
38106
<Platform>x64</Platform>

Directory.Packages.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
<PackageVersion Include="SharpZipLib" Version="1.3.3" />
1414

1515
<!-- Git -->
16-
<PackageVersion Include="LibGit2Sharp.NativeBinaries" Version="2.0.322" />
16+
<!-- libgit2 native library is now provided by vcpkg (see overlays/libgit2) -->
1717

1818
<!-- ProjFS -->
1919
<PackageVersion Include="Microsoft.Windows.ProjFS" Version="2.1.0" />

GVFS/GVFS.Common/GVFS.Common.csproj

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
</PropertyGroup>
66

77
<ItemGroup>
8-
<PackageReference Include="LibGit2Sharp.NativeBinaries" />
98
<PackageReference Include="Microsoft.Data.Sqlite" />
109
<PackageReference Include="SharpZipLib" />
1110
</ItemGroup>

GVFS/GVFS.Hooks/GVFS.Hooks.csproj

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,6 @@
55
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
66
</PropertyGroup>
77

8-
<ItemGroup>
9-
<PackageReference Include="LibGit2Sharp.NativeBinaries" />
10-
</ItemGroup>
11-
128
<ItemGroup>
139
<!--
1410
Files from GVFS.Common included as links here to prevent adding

Readme.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,3 +89,7 @@ See [License.md](License.md).
8989

9090
VFS for Git relies on the PrjFlt filter driver, formerly known as the GvFlt
9191
filter driver, available as a prerelease NuGet package.
92+
93+
VFS for Git also includes or links to third-party native libraries at build
94+
time. See [THIRD-PARTY-NOTICES.md](THIRD-PARTY-NOTICES.md) for details on
95+
these dependencies and their licenses.

THIRD-PARTY-NOTICES.md

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
# Third-Party Notices
2+
3+
VFS for Git incorporates third-party native libraries that are statically
4+
linked into the final executable when building with NativeAOT. This file
5+
documents those dependencies and their licenses.
6+
7+
## libgit2
8+
9+
**Source:** https://github.com/libgit2/libgit2
10+
**Version:** 1.9.3 (via vcpkg overlay port in overlays/libgit2/)
11+
**License:** GPLv2 with Linking Exception
12+
13+
libgit2 is used for local Git object lookups (commit parsing, tree walking,
14+
blob size queries, config reading). VFS for Git calls libgit2 via P/Invoke
15+
and, when building with NativeAOT, statically links the compiled library into
16+
the executable.
17+
18+
The libgit2 COPYING file (https://github.com/libgit2/libgit2/blob/main/COPYING)
19+
includes the following linking exception:
20+
21+
> In addition to the permissions in the GNU General Public License,
22+
> the authors give you unlimited permission to link the compiled
23+
> version of this library into combinations with other programs,
24+
> and to distribute those combinations without any restriction
25+
> coming from the use of this file. (The General Public License
26+
> restrictions do apply in other respects; for example, they cover
27+
> modification of the file, and distribution when not linked into
28+
> a combined executable.)
29+
30+
This exception explicitly permits both dynamic and static linking of the
31+
compiled libgit2 library into VFS for Git without imposing GPL obligations
32+
on VFS for Git's own MIT-licensed source code. Modifications to libgit2
33+
itself remain subject to the GPLv2.
34+
35+
The full GPLv2 license text is available at:
36+
https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
37+
38+
## SQLite
39+
40+
**Source:** https://www.sqlite.org/
41+
**Version:** Bundled via SQLitePCLRaw.lib.e_sqlite3 NuGet package
42+
**License:** Public Domain
43+
44+
SQLite is used for persistent storage of placeholder lists and blob size
45+
caches. The SQLite C library is in the public domain and imposes no
46+
restrictions on linking or distribution.
47+
48+
> The author disclaims copyright to this source code. In place of a
49+
> legal notice, here is a blessing:
50+
>
51+
> May you do good and not evil.
52+
> May you find forgiveness for yourself and forgive others.
53+
> May you share freely, never taking more than you give.
54+
55+
https://www.sqlite.org/copyright.html
56+
57+
## SQLitePCLRaw / Microsoft.Data.Sqlite
58+
59+
**Source:** https://github.com/ericsink/SQLitePCL.raw (SQLitePCLRaw),
60+
https://github.com/dotnet/efcore (Microsoft.Data.Sqlite)
61+
**License:** Apache License 2.0
62+
63+
These managed libraries provide the .NET API surface for SQLite access.
64+
SQLitePCLRaw handles the P/Invoke layer to the native SQLite library, and
65+
Microsoft.Data.Sqlite provides the ADO.NET provider. Both are licensed under
66+
the Apache License 2.0, which permits static linking without restriction.
67+
68+
The full Apache License 2.0 text is available at:
69+
https://www.apache.org/licenses/LICENSE-2.0

overlays/libgit2/README.md

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# libgit2 vcpkg Overlay Port
2+
3+
This overlay replaces the default vcpkg `libgit2` port to pin a specific
4+
version and optionally carry patches ahead of upstream releases.
5+
6+
## Current version
7+
8+
**libgit2 v1.9.3** — includes C4703 warning fixes (libgit2/libgit2#7154)
9+
that were missing from v1.9.1.
10+
11+
## Patches
12+
13+
- `dependencies.diff` — adjusts CMake dependency resolution for vcpkg
14+
(copied from official vcpkg port, required for PCRE discovery)
15+
16+
Additional patches can be added to the `PATCHES` list in `portfile.cmake`
17+
to apply fixes that haven't shipped in an official libgit2 release yet.
18+
19+
## File provenance
20+
21+
All files were copied from the
22+
[official vcpkg libgit2 port](https://github.com/microsoft/vcpkg/tree/master/ports/libgit2)
23+
and then modified as noted below.
24+
25+
| File | Source | Changes |
26+
|------|--------|---------|
27+
| `vcpkg.json` | Official vcpkg port | Unchanged |
28+
| `dependencies.diff` | Official vcpkg port | Unchanged |
29+
| `portfile.cmake` | Official vcpkg port | Removed patches not needed for MSVC x64: `c-standard.diff` (C99 inline keyword — MSVC handles natively), `cli-include-dirs.diff` (CLI tool build — we set `BUILD_CLI=OFF`), `mingw-winhttp.diff` (MinGW only) |
30+
| `README.md` | New | VFSForGit-specific documentation |
31+
32+
When updating to a new libgit2 version, compare these files against the
33+
official vcpkg port to pick up any new patches or portfile changes.
34+
35+
## How overlays work
36+
37+
A vcpkg overlay port **completely replaces** the official port — it doesn't
38+
layer on top. When `--overlay-ports=overlays` is specified, vcpkg uses this
39+
directory's `portfile.cmake` and `vcpkg.json` instead of the registry's.
40+
41+
## Usage
42+
43+
```
44+
vcpkg install --triplet x64-windows-static-aot ^
45+
--overlay-triplets=triplets --overlay-ports=overlays
46+
```

overlays/libgit2/dependencies.diff

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
diff --git a/cmake/SelectRegex.cmake b/cmake/SelectRegex.cmake
2+
index 2a3a91b..523fa72 100644
3+
--- a/cmake/SelectRegex.cmake
4+
+++ b/cmake/SelectRegex.cmake
5+
@@ -1,5 +1,7 @@
6+
# Specify regular expression implementation
7+
-find_package(PCRE)
8+
+find_package(PkgConfig REQUIRED)
9+
+pkg_check_modules(PCRE REQUIRED libpcre)
10+
+set(PCRE_LIBRARIES "${PCRE_LINK_LIBRARIES}")
11+
12+
if(REGEX_BACKEND STREQUAL "")
13+
check_symbol_exists(regcomp_l "regex.h;xlocale.h" HAVE_REGCOMP_L)

0 commit comments

Comments
 (0)