forked from UbiquityDotNET/Llvm.NET
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Build-Interop.ps1
153 lines (134 loc) · 8.43 KB
/
Build-Interop.ps1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
<#
.SYNOPSIS
Builds the native code Extended LLVM C API DLL along with the interop .NET assembly for it
.PARAMETER Configuration
This sets the build configuration to use, default is "Release" though for inner loop development this may be set to "Debug"
.PARAMETER AllowVsPreReleases
Switch to enable use of Visual Studio Pre-Release versions. This is NEVER enabled for official production builds, however it is
useful when adding support for new versions during the pre-release stages.
.PARAMETER FullInit
Performs a full initialization. A full initialization includes forcing a re-capture of the time stamp for local builds
as well as writes details of the initialization to the information and verbose streams.
.NOTE
This script is unfortunately necessary due to several factors:
1. SDK projects cannot reference VCXPROJ files correctly since they are multi-targeting
and VCXproj projects are not
2. CppSharp NUGET package is basically hostile to SDK projects and would otherwise require
the use of packages.config
3. packages.config NUGET is hostile to shared version control as it insists on placing full
paths to the NuGet dependencies and build artifacts into the project file. (e.g. adding a
NuGet dependency modifies the project file to inject hard coded FULL paths guaranteed to
fail on any version controlled project when built on any other machine)
4. Common resolution to #3 is to use a Nuget.Config to re-direct packages to a well known
location relative to the build root. However, that doesn't work since CppSharp and its
weird copy output folder dependency has hard coded assumptions of a "packages" folder
at the solution level.
5. Packing the final NugetPackage needs the output of the native code project AND that of
the managed interop library. But as stated in #1 there can't be a dependency so something
has to manage the build ordering independent of the multi-targeting.
The solution to all of the above is a combination of elements
1. The LlvmBindingsGenerator is an SDK project. This effectively disables the gross copy
output hack and allows the use of project references. (Though on it's own is not enough
as the CppSharp assemblies aren't available to the build)
2. The LlvmBindingsGenerator.csproj has a custom "None" ItemGroup that copies the CppSharp
libs to the output directory so that the build can complete. (Though it requires a restore
pass to work so that the items are copied during restore and available at build)
3. This script to control the ordering of the build so that the native code is built, then the
interop lib is restored and finally the interop lib is built with multi-targeting.
4. The interop assembly project includes the NuGet packing with "content" references to the
native assemblies to place the binaries in the correct "native" "runtimes" folder for NuGet
to handle them.
#>
Param(
[string]$Configuration="Release",
[switch]$AllowVsPreReleases,
[switch]$FullInit
)
pushd $PSScriptRoot
$oldPath = $env:Path
try
{
. .\repo-buildutils.ps1
$buildInfo = Initialize-BuildEnvironment -FullInit:$FullInit -AllowVsPreReleases:$AllowVsPreReleases
# <HACK>
# for details of why this is needed, see src\PatchVsForLibClang\readme.md
# min version with fix (VS 2019 16.9 preview 2)
$minOfficialVersion = [System.Version]('16.9.30803.129')
Write-Information "Building PatchVsForLibClang.exe"
$msBuildProperties = @{ Configuration = 'Release'}
$buildLogPath = Join-Path $buildInfo['BinLogsPath'] PatchVsForLibClang.binlog
Invoke-MSBuild -Targets 'Restore;Build' -Project src\PatchVsForLibClang\PatchVsForLibClang.sln -Properties $msBuildProperties -LoggerArgs ($buildInfo['MsBuildLoggerArgs'] + @("/bl:$buildLogPath") )
$vs = Find-VSInstance -AllowVsPreReleases:$AllowVsPreReleases
if($vs.InstallationVersion -lt $minOfficialVersion)
{
pushd (Join-Path $buildInfo.BuildOutputPath 'bin\PatchVsForLibClang\Release\netcoreapp3.1')
try
{
Write-Information "Patching VS CRT for parsing with LibClang..."
.\PatchVsForLibClang.exe $vs.InstallationPath
}
finally
{
popd
}
}
else
{
Write-Information "$($vs.DisplayName) ($($vs.InstallationVersion)) already includes the official patch - skipping manual patch"
}
#</HACK>
# Download and unpack the LLVM libs if not already present, this doesn't use NuGet as the NuGet compression
# is insufficient to keep the size reasonable enough to support posting to public galleries. Additionally, the
# support for native lib projects in NuGet is tenuous at best. Due to various compiler version dependencies
# and incompatibilities libs are generally not something published in a package. However, since the build time
# for the libraries exceeds the time allowed for most hosted build services these must be pre-built for the
# automated builds.
Install-LlvmLibs $buildInfo
$msBuildProperties = @{ Configuration = $Configuration
LlvmVersion = $buildInfo['LlvmVersion']
}
Write-Information "Building LllvmBindingsGenerator"
$generatorRestoreBuildLogPath = Join-Path $buildInfo['BinLogsPath'] LlvmBindingsGeneratorRestore.binlog
$generatorBuildLogPath = Join-Path $buildInfo['BinLogsPath'] LlvmBindingsGenerator.binlog
# manual restore needed so that the CppSharp libraries are available during the build phase
Invoke-MSBuild -Targets 'Restore' -Project 'src\Interop\LlvmBindingsGenerator\LlvmBindingsGenerator.csproj' -Properties $msBuildProperties -LoggerArgs ($buildInfo['MsBuildLoggerArgs'] + @("/bl:$generatorRestoreBuildLogPath"))
Invoke-MSBuild -Targets 'Build' -Project 'src\Interop\LlvmBindingsGenerator\LlvmBindingsGenerator.csproj' -Properties $msBuildProperties -LoggerArgs ($buildInfo['MsBuildLoggerArgs'] + @("/bl:$generatorBuildLogPath"))
# At present CppSharp only supports the "desktop" framework, so limiting this to net47 for now
# Hopefully they will support .NET Core soon, if not, the generation stage may need to move out
# to a manual step with the results checked in.
Write-Information "Generating P/Invoke Bindings"
Write-Information "LlvmBindingsGenerator.exe $($buildInfo['LlvmLibsRoot']) $(Join-Path $buildInfo['SrcRootPath'] 'Interop\LibLLVM') $(Join-Path $buildInfo['SrcRootPath'] 'Interop\Ubiquity.NET.Llvm.Interop')"
& "$($buildInfo['BuildOutputPath'])\bin\LlvmBindingsGenerator\Release\net5.0-windows\LlvmBindingsGenerator.exe" $buildInfo['LlvmLibsRoot'] (Join-Path $buildInfo['SrcRootPath'] 'Interop\LibLLVM') (Join-Path $buildInfo['SrcRootPath'] 'Interop\Ubiquity.NET.Llvm.Interop')
if($LASTEXITCODE -eq 0)
{
# now build the projects that consume generated output for the bindings
# Need to invoke NuGet directly for restore of vcxproj as /t:Restore target doesn't support packages.config
# and PackageReference isn't supported for native projects... [Sigh...]
Write-Information "Restoring LibLLVM"
Invoke-NuGet restore 'src\Interop\LibLLVM\LibLLVM.vcxproj'
Write-Information "Building LibLLVM"
$libLLVMBinLogPath = Join-Path $buildInfo['BinLogsPath'] LibLLVM-Build.binlog
Invoke-MSBuild -Targets 'Build' -Project 'src\Interop\LibLLVM\LibLLVM.vcxproj' -Properties $msBuildProperties -LoggerArgs ($buildInfo['MsBuildLoggerArgs'] + @("/bl:$libLLVMBinLogPath") )
Write-Information "Building Ubiquity.NET.Llvm.Interop"
$interopSlnBinLog = Join-Path $buildInfo['BinLogsPath'] Interop.sln.binlog
Invoke-MSBuild -Targets 'Restore;Build' -Project 'src\Interop\Interop.sln' -Properties $msBuildProperties -LoggerArgs ($buildInfo['MsBuildLoggerArgs'] + @("/bl:$interopSlnBinLog") )
}
else
{
Write-Error "Generating LLVM Bindings failed" -ErrorAction Stop
}
}
catch
{
# everything from the official docs to the various articles in the blog-sphere says this isn't needed
# and in fact it is redundant - They're all WRONG! By re-throwing the exception the original location
# information is retained and the error reported will include the correct source file and line number
# data for the error. Without this, only the error message is retained and the location information is
# Line 1, Column 1, of the outer most script file, which is, of course, completely useless.
throw
}
finally
{
popd
$env:Path = $oldPath
}