Skip to content

Commit b6e32f9

Browse files
committed
Give each vcpkg triplet its own install root
1 parent a769cb2 commit b6e32f9

4 files changed

Lines changed: 113 additions & 28 deletions

File tree

‎Directory.Build.props‎

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,13 @@
2929
<TelegramVcpkgTriplet Condition="'$(Platform)' == 'x64'">x64-uwp</TelegramVcpkgTriplet>
3030
<TelegramVcpkgTriplet Condition="'$(Platform)' == 'ARM64'">arm64-uwp</TelegramVcpkgTriplet>
3131

32-
<!-- Left to itself the MSBuild integration appends the triplet twice (it passes
33-
vcpkg_installed\<triplet> as the install root and vcpkg creates <triplet> inside it),
34-
which would not match the layout CMake uses for the TDLib build. Pin it so both land in
35-
the same tree and openssl is built once. -->
36-
<VcpkgInstalledDir>$(TelegramRoot)vcpkg_installed\</VcpkgInstalledDir>
32+
<!-- One install root per triplet - the layout the integration uses left to itself, where the
33+
triplet appears twice because vcpkg creates <triplet> inside the root it is handed. It
34+
cannot be flattened into a shared root: a manifest install root belongs to a single
35+
triplet, and vcpkg purges whatever is outside the plan it just computed, so building
36+
ARM64 would take the x64 packages with it. The TDLib build is pointed at the same roots,
37+
so openssl is still built once per triplet and shared with tdjson.dll. -->
38+
<VcpkgInstalledDir>$(TelegramRoot)vcpkg_installed\$(TelegramVcpkgTriplet)\</VcpkgInstalledDir>
3739
<TelegramVcpkgInstalledDir>$(VcpkgInstalledDir)$(TelegramVcpkgTriplet)\</TelegramVcpkgInstalledDir>
3840
<TelegramVcpkgBinDir Condition="'$(Configuration)' == 'Debug'">$(TelegramVcpkgInstalledDir)debug\bin\</TelegramVcpkgBinDir>
3941
<TelegramVcpkgBinDir Condition="'$(TelegramVcpkgBinDir)' == ''">$(TelegramVcpkgInstalledDir)bin\</TelegramVcpkgBinDir>

‎Directory.Build.targets‎

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,31 @@
6464
Text="The vcpkg checkout at $(VcpkgRoot) is older than the commit pinned in vcpkg.json. Run: git -C &quot;$(VcpkgRoot)&quot; fetch &amp;&amp; git -C &quot;$(VcpkgRoot)&quot; checkout $(_TelegramVcpkgBaseline) &amp;&amp; &quot;$(VcpkgRoot)\bootstrap-vcpkg.bat&quot;" />
6565
</Target>
6666

67+
<!--
68+
The integration skips its install whenever its stamp file is newer than the manifest, so an
69+
installed tree emptied behind its back - by hand, or by a vcpkg install pointed at the same
70+
root for another triplet - is never noticed, and the build fails on a missing header instead.
71+
Drop the stamp when the tree is gone, and the install runs again.
72+
-->
73+
<Target Name="TelegramInvalidateVcpkgStamp" BeforeTargets="VcpkgInstallManifestDependencies"
74+
Condition="'$(TelegramUsesVcpkg)' == 'true' And '$(MSBuildProjectExtension)' == '.vcxproj' And !Exists('$(TelegramVcpkgInstalledDir)include')">
75+
<ItemGroup>
76+
<_TelegramVcpkgStamp Include="$(VcpkgInstalledDir).msbuildstamp-$(TelegramVcpkgTriplet)*" />
77+
</ItemGroup>
78+
<Delete Files="@(_TelegramVcpkgStamp)" />
79+
</Target>
80+
81+
<!--
82+
The safety net for the above, since the stamp file is vcpkg's private detail: if the tree is
83+
still not there once the install has had its chance, say so here rather than in whichever
84+
header happens to be included first.
85+
-->
86+
<Target Name="TelegramCheckVcpkgInstalled" AfterTargets="VcpkgInstallManifestDependencies"
87+
Condition="'$(TelegramUsesVcpkg)' == 'true' And '$(MSBuildProjectExtension)' == '.vcxproj'">
88+
<Error Condition="!Exists('$(TelegramVcpkgInstalledDir)include')"
89+
Text="vcpkg installed nothing into $(TelegramVcpkgInstalledDir). Delete $(VcpkgInstalledDir) and build again." />
90+
</Target>
91+
6792
<!--
6893
Put the vcpkg runtime DLLs both in the output folder (so F5 works) and in the package.
6994
Both destinations are fed from ReferenceCopyLocalPaths: the native projects copy them next to
@@ -87,7 +112,10 @@
87112
Exclude="$(TelegramVcpkgBinDir)zlib1.dll;$(TelegramVcpkgBinDir)libcrypto-3*.dll;$(TelegramVcpkgBinDir)libssl-3*.dll;$(TelegramVcpkgBinDir)legacy.dll" />
88113
<ReferenceCopyLocalPaths Include="@(TelegramVcpkgRuntimeDll)" />
89114
</ItemGroup>
90-
<Warning Condition="'@(TelegramVcpkgRuntimeDll)' == ''"
115+
<!-- Only the app projects warn. A native project reaches ResolveReferences before its own
116+
vcpkg install has run, so on a tree that has yet to be restored it would always fire;
117+
TelegramCheckVcpkgInstalled is what covers those. -->
118+
<Warning Condition="'@(TelegramVcpkgRuntimeDll)' == '' And '$(MSBuildProjectExtension)' == '.csproj'"
91119
Text="No vcpkg runtime DLLs found in $(TelegramVcpkgBinDir). The package will be missing them at runtime." />
92120
</Target>
93121

‎Documentation/Build-instructions.md‎

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -67,15 +67,16 @@ machine-wide integration so that it always builds against its own pinned commit.
6767
Everything else comes from `vcpkg.json` in the repository root, which is a
6868
[manifest](https://learn.microsoft.com/vcpkg/consume/manifest-mode): it pins the vcpkg commit
6969
(`builtin-baseline`) and lists the libraries, and the build restores them on demand into
70-
`vcpkg_installed\<triplet>`.
70+
`vcpkg_installed\<triplet>\<triplet>` — one install root per architecture, the triplet repeated
71+
because vcpkg creates its own `<triplet>` folder inside the root it is given.
7172

7273
ffmpeg has to be built with a specific set of decoders, so it is vendored as an
7374
[overlay port](https://learn.microsoft.com/vcpkg/concepts/overlay-ports) in
7475
`Libraries\vcpkg-ports\ffmpeg`, taken from the vcpkg registry with the `--enable-*` list applied
7576
on top. It takes precedence over whichever ffmpeg version the pinned commit happens to carry.
7677

77-
TDLib is built from the same manifest and the same installed tree, so the openssl and zlib it
78-
links are the ones the app ships.
78+
TDLib is built from the same manifest and into the same roots, so the openssl and zlib it links
79+
are the ones the app ships.
7980

8081
### TDLib
8182
In order to communicate with Telegram servers, Unigram uses TDLib. It comes as a submodule and is
@@ -91,12 +92,13 @@ Two extra tools are needed for the code generation step:
9192
Then, from `Libraries\tdjson`:
9293

9394
```shell
94-
> powershell -ExecutionPolicy ByPass ./build.ps1 -arch x64,ARM64
95+
> powershell -ExecutionPolicy ByPass ./build.ps1
9596
```
9697

97-
The script picks up `VCPKG_ROOT` and builds against the manifest in the repository root, so
98-
openssl and zlib are the same builds the app links. You can choose to build both `x64` and
99-
`arm64` or just the architecture you need.
98+
The script finds vcpkg exactly as the rest of the build does — it asks MSBuild to evaluate
99+
`Directory.Build.props` — and builds against the manifest in the repository root, so openssl
100+
and zlib are the same builds the app links. Both architectures are built by default; pass
101+
`-arch x64` or `-arch ARM64` for one of them.
100102

101103
### LibVLC and WebRTC
102104

‎Libraries/tdjson/build.ps1‎

Lines changed: 68 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,20 @@
11
param (
2-
[string]$vcpkg_root = $(if ($env:VCPKG_ROOT) { $env:VCPKG_ROOT } else { throw "-vcpkg_root=<path to vcpkg> is required, or set VCPKG_ROOT" }),
3-
[ValidateSet('x86', 'x64', 'ARM', 'ARM64', IgnoreCase = $false)]
4-
[string[]]$arch = @( "x86", "x64", "ARM", "ARM64" ),
2+
[string]$vcpkg_root,
3+
# x86 and ARM are not offered: libvlc and webrtc declare "supports": "uwp & (x64 | arm64)", so a
4+
# manifest install for either fails before TDLib is reached, and the app has no such platform.
5+
[ValidateSet('x64', 'ARM64', IgnoreCase = $false)]
6+
[string[]]$arch = @( "x64", "ARM64" ),
57
[string]$mode = "all"
68
)
79
$ErrorActionPreference = "Stop"
810

9-
$vcpkg_root = Resolve-Path $vcpkg_root
10-
11-
$vcpkg_cmake="${vcpkg_root}\scripts\buildsystems\vcpkg.cmake"
1211
$arch_list = $arch
12+
1313
$td_root = Resolve-Path "../tdlib"
1414

15-
# TDLib and the app share one manifest and one installed tree, so that openssl and zlib cannot
16-
# drift between the tdjson.dll we ship and the copies the app links against.
15+
# TDLib and the app share one manifest, so that openssl and zlib cannot drift between the
16+
# tdjson.dll we ship and the copies the app links against.
1717
$manifest_root = Resolve-Path "../.."
18-
$installed_root = Join-Path $manifest_root "vcpkg_installed"
1918

2019
function CheckLastExitCode {
2120
if ($LastExitCode -ne 0) {
@@ -27,6 +26,60 @@ CALLSTACK:$(Get-PSCallStack | Out-String)
2726
}
2827
}
2928

29+
# Which vcpkg, where it installs and under which triplet are all decided in Directory.Build.props.
30+
# Evaluate it per platform rather than repeating any of that here: the installed tree in particular
31+
# is one root per triplet, and a build that guessed the layout would install beside the app's tree
32+
# instead of into it - or, sharing a root across triplets, purge it.
33+
function ResolveVcpkgPaths {
34+
param([string]$platform)
35+
36+
$installer = Join-Path ${env:ProgramFiles(x86)} "Microsoft Visual Studio\Installer"
37+
$vswhere = Join-Path $installer "vswhere.exe"
38+
if (-not (Test-Path $vswhere)) {
39+
throw "vswhere.exe not found at $vswhere"
40+
}
41+
42+
$vs = & $vswhere -latest -prerelease -products * -requires Microsoft.Component.MSBuild -property installationPath
43+
if (-not $vs) {
44+
throw "No Visual Studio installation with MSBuild was found."
45+
}
46+
47+
$msbuild = Join-Path $vs "MSBuild\Current\Bin\amd64\MSBuild.exe"
48+
if (-not (Test-Path $msbuild)) {
49+
throw "MSBuild.exe not found at $msbuild"
50+
}
51+
52+
# -getProperty evaluates the project, it does not build it. The stub imports the props file on
53+
# its own, so none of the C++ targets are involved; TelegramUsesVcpkg is what gates the property
54+
# there, and an explicit -vcpkg_root arrives as the global property the chain checks first.
55+
$props = Join-Path $manifest_root "Directory.Build.props"
56+
$stub = Join-Path ([System.IO.Path]::GetTempPath()) "tdjson-vcpkg-root-$PID.proj"
57+
Set-Content -LiteralPath $stub -Value "<Project><Import Project=`"$props`" /></Project>"
58+
59+
Try {
60+
$arguments = @($stub, "-nologo", "-p:TelegramUsesVcpkg=true", "-p:Platform=$platform",
61+
"-getProperty:VcpkgRoot,VcpkgInstalledDir,TelegramVcpkgTriplet")
62+
if ($vcpkg_root) {
63+
$arguments += "-p:VcpkgRoot=$((Resolve-Path $vcpkg_root).Path)"
64+
}
65+
$json = (& $msbuild @arguments | Out-String)
66+
CheckLastExitCode
67+
} Finally {
68+
Remove-Item $stub -Force -ErrorAction SilentlyContinue
69+
}
70+
71+
$resolved = ($json | ConvertFrom-Json).Properties
72+
73+
if (-not $resolved.VcpkgRoot) {
74+
throw "vcpkg was not found. Clone it next to this repository, install the vcpkg component in the Visual Studio installer, or set VCPKG_ROOT - see Documentation/Build-instructions.md."
75+
}
76+
if (-not $resolved.TelegramVcpkgTriplet) {
77+
throw "The app defines no vcpkg triplet for platform $platform, so TDLib cannot be built against the tree it uses."
78+
}
79+
80+
return $resolved
81+
}
82+
3083
function clean {
3184
Remove-Item build-* -Force -Recurse -ErrorAction SilentlyContinue
3285
}
@@ -53,12 +106,12 @@ function config {
53106
New-Item -ItemType Directory -Force -Path $arch
54107
cd $arch
55108
echo "${td_root}"
56-
$fixed_arch = $arch
57-
if ($arch -eq "x86") {
58-
$fixed_arch = "win32"
59-
}
60-
$triplet = "$($arch.ToLower())-uwp"
61-
cmake -A $fixed_arch -DCMAKE_SYSTEM_VERSION="10.0" -DCMAKE_SYSTEM_NAME="WindowsStore" -DCMAKE_TOOLCHAIN_FILE="$vcpkg_cmake" -DVCPKG_MANIFEST_DIR="$manifest_root" -DVCPKG_INSTALLED_DIR="$installed_root" -DVCPKG_TARGET_TRIPLET="$triplet" -DTD_ENABLE_MULTI_PROCESSOR_COMPILATION=ON "$td_root"
109+
$vcpkg = ResolveVcpkgPaths $arch
110+
$vcpkg_cmake = Join-Path $vcpkg.VcpkgRoot "scripts\buildsystems\vcpkg.cmake"
111+
# Trailing backslashes are trimmed: cmake.exe parses \" as an escaped quote, and MSBuild hands
112+
# directory properties back with one.
113+
$installed_root = $vcpkg.VcpkgInstalledDir.TrimEnd('\')
114+
cmake -A $arch -DCMAKE_SYSTEM_VERSION="10.0" -DCMAKE_SYSTEM_NAME="WindowsStore" -DCMAKE_TOOLCHAIN_FILE="$vcpkg_cmake" -DVCPKG_MANIFEST_DIR="$manifest_root" -DVCPKG_INSTALLED_DIR="$installed_root" -DVCPKG_TARGET_TRIPLET="$($vcpkg.TelegramVcpkgTriplet)" -DTD_ENABLE_MULTI_PROCESSOR_COMPILATION=ON "$td_root"
62115
CheckLastExitCode
63116
cd ..
64117
}

0 commit comments

Comments
 (0)