Skip to content

Commit c1f3c04

Browse files
author
s-a
committed
add runtime flag to relve native lib binding correctly
1 parent e6e51ae commit c1f3c04

File tree

1 file changed

+55
-216
lines changed

1 file changed

+55
-216
lines changed

scripts/build.ps1

Lines changed: 55 additions & 216 deletions
Original file line numberDiff line numberDiff line change
@@ -26,41 +26,11 @@ Set-Location $ProjectRoot
2626
# Step 1: Check prerequisites
2727
Write-Host "🔍 Checking prerequisites..." -ForegroundColor Yellow
2828

29-
# Check for Git
3029
if (-not (Get-Command git -ErrorAction SilentlyContinue)) {
31-
Write-Error "Git is required but not found in PATH"
32-
exit 1
30+
Write-Error "Git is required but not found in PATH"; exit 1
3331
}
34-
35-
# Check for .NET SDK
3632
if (-not (Get-Command dotnet -ErrorAction SilentlyContinue)) {
37-
Write-Error ".NET SDK is required but not found in PATH"
38-
exit 1
39-
}
40-
41-
# Check for Visual Studio Build Tools
42-
$MSBuildPaths = @(
43-
"${env:ProgramFiles}\Microsoft Visual Studio\2022\Enterprise\MSBuild\Current\Bin\MSBuild.exe",
44-
"${env:ProgramFiles}\Microsoft Visual Studio\2022\Professional\MSBuild\Current\Bin\MSBuild.exe",
45-
"${env:ProgramFiles}\Microsoft Visual Studio\2022\Community\MSBuild\Current\Bin\MSBuild.exe",
46-
"${env:ProgramFiles}\Microsoft Visual Studio\2022\BuildTools\MSBuild\Current\Bin\MSBuild.exe",
47-
"${env:ProgramFiles(x86)}\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin\MSBuild.exe",
48-
"${env:ProgramFiles(x86)}\Microsoft Visual Studio\2019\Professional\MSBuild\Current\Bin\MSBuild.exe",
49-
"${env:ProgramFiles(x86)}\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\MSBuild.exe",
50-
"${env:ProgramFiles(x86)}\Microsoft Visual Studio\2019\BuildTools\MSBuild\Current\Bin\MSBuild.exe"
51-
)
52-
53-
$MSBuild = $null
54-
foreach ($path in $MSBuildPaths) {
55-
if (Test-Path $path) {
56-
$MSBuild = $path
57-
break
58-
}
59-
}
60-
61-
if (-not $MSBuild) {
62-
Write-Warning "⚠️ MSBuild not found. Native library compilation may fail."
63-
Write-Host "Please install Visual Studio Build Tools 2019 or later"
33+
Write-Error ".NET SDK is required but not found in PATH"; exit 1
6434
}
6535

6636
# Step 2: Clone and prepare libpg_query
@@ -81,281 +51,150 @@ if (-not $SkipNative) {
8151
Set-Location ..
8252
}
8353

84-
# Build libpg_query using Windows Makefile
8554
Write-Host "🔨 Building libpg_query for Windows..." -ForegroundColor Yellow
8655
Set-Location libpg_query
8756

88-
if ($MSBuild) {
89-
# Try to build with Visual Studio
90-
if (Test-Path "Makefile.msvc") {
91-
Write-Host "Using Visual Studio tools..."
92-
& nmake /F Makefile.msvc clean
93-
& nmake /F Makefile.msvc
94-
}
95-
else {
96-
Write-Warning "Makefile.msvc not found, trying alternative approach..."
97-
# Fallback: try to use make with WSL or similar
98-
if (Get-Command make -ErrorAction SilentlyContinue) {
99-
& make clean
100-
& make
101-
}
102-
else {
103-
Write-Error "Cannot build libpg_query. Please install Visual Studio Build Tools or WSL."
104-
exit 1
105-
}
106-
}
57+
if (Test-Path "Makefile.msvc") {
58+
Write-Host "Using Visual Studio tools (nmake)..."
59+
& nmake /F Makefile.msvc clean
60+
& nmake /F Makefile.msvc
61+
}
62+
else {
63+
Write-Error "Makefile.msvc not found in libpg_query. Cannot proceed with Windows build."
64+
exit 1
10765
}
10866

10967
Set-Location $ProjectRoot
11068

111-
# Step 2b: Build wrapper library (FINAL FIX)
69+
# Step 2b: Build wrapper library
11270
Write-Host "🔧 Building wrapper library..." -ForegroundColor Yellow
11371

114-
# --- ADD CLEANUP STEP ---
11572
Write-Host "🧹 Cleaning up old build artifacts..."
11673
Remove-Item -Path "wrapper.c", "wrapper.def", "libpgquery_wrapper.dll" -ErrorAction SilentlyContinue
11774

11875
$WrapperPath = Join-Path $ProjectRoot "wrapper.c"
11976
$DefPath = Join-Path $ProjectRoot "wrapper.def"
12077

121-
# Create the wrapper.c file, forcing __stdcall calling convention to match .NET's P/Invoke default
12278
Write-Host "Creating wrapper.c with __stdcall calling convention..."
12379
@"
12480
#include "libpg_query/pg_query.h"
125-
126-
// Forcing __stdcall is crucial for default .NET P/Invoke on Windows
12781
#define STDCALL __stdcall
12882
129-
PgQueryProtobufParseResult STDCALL pg_query_parse_protobuf_wrapper(const char* input) {
130-
return pg_query_parse_protobuf(input);
131-
}
132-
133-
PgQueryProtobufParseResult STDCALL pg_query_parse_protobuf_opts_wrapper(const char* input, int parser_options) {
134-
return pg_query_parse_protobuf_opts(input, parser_options);
135-
}
136-
137-
void STDCALL pg_query_free_protobuf_parse_result_wrapper(PgQueryProtobufParseResult result) {
138-
pg_query_free_protobuf_parse_result(result);
139-
}
140-
141-
PgQueryDeparseResult STDCALL pg_query_deparse_protobuf_wrapper(PgQueryProtobuf parse_tree) {
142-
return pg_query_deparse_protobuf(parse_tree);
143-
}
144-
145-
PgQueryParseResult STDCALL pg_query_parse_wrapper(const char* input) {
146-
return pg_query_parse(input);
147-
}
148-
149-
void STDCALL pg_query_free_parse_result_wrapper(PgQueryParseResult result) {
150-
pg_query_free_parse_result(result);
151-
}
152-
153-
PgQueryNormalizeResult STDCALL pg_query_normalize_wrapper(const char* input) {
154-
return pg_query_normalize(input);
155-
}
156-
157-
void STDCALL pg_query_free_normalize_result_wrapper(PgQueryNormalizeResult result) {
158-
pg_query_free_normalize_result(result);
159-
}
83+
PgQueryProtobufParseResult STDCALL pg_query_parse_protobuf_wrapper(const char* input) { return pg_query_parse_protobuf(input); }
84+
void STDCALL pg_query_free_protobuf_parse_result_wrapper(PgQueryProtobufParseResult result) { pg_query_free_protobuf_parse_result(result); }
85+
PgQueryParseResult STDCALL pg_query_parse_wrapper(const char* input) { return pg_query_parse(input); }
86+
void STDCALL pg_query_free_parse_result_wrapper(PgQueryParseResult result) { pg_query_free_parse_result(result); }
87+
PgQueryNormalizeResult STDCALL pg_query_normalize_wrapper(const char* input) { return pg_query_normalize(input); }
88+
void STDCALL pg_query_free_normalize_result_wrapper(PgQueryNormalizeResult result) { pg_query_free_normalize_result(result); }
16089
"@ | Set-Content -Path $WrapperPath -Encoding Ascii
16190

162-
# Create the .def file to export the wrapper functions with undecorated names
16391
Write-Host "Creating wrapper.def to export functions..."
16492
@"
16593
EXPORTS
16694
pg_query_parse_protobuf_wrapper
167-
pg_query_parse_protobuf_opts_wrapper
16895
pg_query_free_protobuf_parse_result_wrapper
169-
pg_query_deparse_protobuf_wrapper
17096
pg_query_parse_wrapper
17197
pg_query_free_parse_result_wrapper
17298
pg_query_normalize_wrapper
17399
pg_query_free_normalize_result_wrapper
174100
"@ | Set-Content -Path $DefPath -Encoding Ascii
175101

176102
$ClPath = Get-Command cl.exe -ErrorAction SilentlyContinue
177-
if (-not $ClPath) {
178-
Write-Error "cl.exe not found. Ensure Visual Studio Build Tools are installed and vcvars are loaded."
179-
exit 1
180-
}
103+
if (-not $ClPath) { Write-Error "cl.exe not found. Ensure Visual Studio Build Tools are installed and vcvars are loaded."; exit 1 }
181104

182-
# Compile the wrapper, linking the real library and using the .def file for exports.
183105
& $ClPath /nologo /LD /I "libpg_query" $WrapperPath "libpg_query\pg_query.lib" /DEF:$DefPath /link /OUT:libpgquery_wrapper.dll
184-
if ($LASTEXITCODE -ne 0) {
185-
Write-Error "❌ Failed to compile wrapper library"
186-
exit $LASTEXITCODE
187-
}
106+
if ($LASTEXITCODE -ne 0) { Write-Error "❌ Failed to compile wrapper library"; exit $LASTEXITCODE }
188107
}
189108

190109
# Step 3: Create runtime directories and copy libraries
191110
if (-not $SkipNative) {
192111
Write-Host "📁 Setting up runtime directories..." -ForegroundColor Yellow
193-
194112
$RuntimeDir = "runtimes\$TargetRid\native"
195113
New-Item -Path $RuntimeDir -ItemType Directory -Force | Out-Null
196114

197-
# Define source locations for libraries
198115
$LibraryMappings = @{
199-
"libpg_query.dll" = @("libpg_query\libpg_query.dll", "libpg_query\pg_query.dll")
200-
"libpg_query.lib" = @("libpg_query\libpg_query.lib", "libpg_query\pg_query.lib")
201-
"libpgquery_wrapper.dll" = @("libpgquery_wrapper.dll", "libpg_query\libpgquery_wrapper.dll")
202-
"pg_query.dll" = @("libpg_query\pg_query.dll")
116+
"libpgquery_wrapper.dll" = @("libpgquery_wrapper.dll")
203117
}
204118

205119
foreach ($targetLib in $LibraryMappings.Keys) {
206-
$copied = $false
207-
foreach ($sourcePath in $LibraryMappings[$targetLib]) {
208-
if (Test-Path $sourcePath) {
209-
Write-Host "Copying $sourcePath to $RuntimeDir\$targetLib"
210-
Copy-Item $sourcePath "$RuntimeDir\$targetLib" -Force
211-
$copied = $true
212-
break
213-
}
120+
$sourcePath = $LibraryMappings[$targetLib][0]
121+
if (Test-Path $sourcePath) {
122+
Write-Host "Copying $sourcePath to $RuntimeDir\$targetLib"
123+
Copy-Item $sourcePath "$RuntimeDir\$targetLib" -Force
214124
}
215-
if (-not $copied) {
216-
# This is expected for libpg_query.dll on Windows, as only the .lib is built. The wrapper serves as the DLL.
217-
if ($targetLib -ne "libpg_query.dll" -and $targetLib -ne "pg_query.dll") {
218-
Write-Warning "⚠️ Could not find source for $targetLib"
219-
}
125+
else {
126+
Write-Warning "⚠️ Could not find source for $targetLib"
220127
}
221128
}
222129

223-
# Also copy to project runtimes directory
224130
$ProjectRuntimeDir = "src\GrepSQL\runtimes\$TargetRid\native"
225131
New-Item -Path $ProjectRuntimeDir -ItemType Directory -Force | Out-Null
226-
227-
# Copy from the main runtime directory to project directory
228132
Get-ChildItem $RuntimeDir -File | ForEach-Object {
229133
Write-Host "Copying $($_.Name) to $ProjectRuntimeDir"
230134
Copy-Item $_.FullName $ProjectRuntimeDir -Force
231135
}
232136

233-
# Verify critical files exist
234-
$CriticalFiles = @("libpgquery_wrapper.dll")
235-
foreach ($file in $CriticalFiles) {
236-
$projectPath = Join-Path $ProjectRuntimeDir $file
237-
if (-not (Test-Path $projectPath)) {
238-
Write-Error "❌ Critical file $file not found in $ProjectRuntimeDir"
239-
exit 1
240-
}
241-
else {
242-
Write-Host "✅ Verified $file exists in $ProjectRuntimeDir" -ForegroundColor Green
243-
}
244-
}
137+
$criticalFile = Join-Path $ProjectRuntimeDir "libpgquery_wrapper.dll"
138+
if (-not (Test-Path $criticalFile)) { Write-Error "❌ Critical file libpgquery_wrapper.dll not found in $ProjectRuntimeDir"; exit 1 }
139+
else { Write-Host "✅ Verified libpgquery_wrapper.dll exists in $ProjectRuntimeDir" -ForegroundColor Green }
245140
}
246141

247142
# Step 4: Generate protobuf files
248143
if (-not $SkipProtobuf) {
249144
Write-Host "🔧 Generating protobuf files..." -ForegroundColor Yellow
250-
251-
# Check for protoc
252-
$ProtocPath = Get-Command protoc -ErrorAction SilentlyContinue
253-
if (-not $ProtocPath) {
254-
Write-Warning "⚠️ protoc not found. Attempting to install via dotnet tool..."
255-
& dotnet tool install --global protobuf-net.Protogen --version 3.2.26
256-
257-
# Try again
258-
$ProtocPath = Get-Command protoc -ErrorAction SilentlyContinue
259-
if (-not $ProtocPath) {
260-
Write-Error "❌ Could not find or install protoc. Please install Protocol Buffers compiler manually."
261-
exit 1
262-
}
263-
}
264-
265-
# Add Grpc.Tools if not present
266-
$GrpcToolsPath = "$env:USERPROFILE\.nuget\packages\grpc.tools"
267-
if (-not (Test-Path $GrpcToolsPath)) {
268-
Write-Host "Installing Grpc.Tools..."
269-
& dotnet add "src\GrepSQL" package Grpc.Tools --version 2.72.0
145+
if (-not (Get-Command protoc -ErrorAction SilentlyContinue)) {
146+
Write-Warning "⚠️ protoc not found. Please ensure it's installed and in the PATH."
270147
}
271-
272-
# Find the latest version and appropriate platform tools
273-
$LatestVersion = Get-ChildItem $GrpcToolsPath | Sort-Object Name -Descending | Select-Object -First 1
274-
$PluginPath = "$($LatestVersion.FullName)\tools\windows_x64"
275-
276-
if (-not (Test-Path $PluginPath)) {
277-
$PluginPath = "$($LatestVersion.FullName)\tools\windows_x86"
148+
if (-not (Test-Path "$env:USERPROFILE\.nuget\packages\grpc.tools")) {
149+
Write-Host "Installing Grpc.Tools NuGet package..."
150+
& dotnet add "src\GrepSQL" package Grpc.Tools
278151
}
279152

280-
$env:PATH = "$env:PATH;$PluginPath"
281-
282-
# Generate protobuf files
283153
$ProtoSrc = "libpg_query\protobuf"
284154
$ProtoOut = "src\GrepSQL\AST\Generated"
285-
286155
New-Item -Path $ProtoOut -ItemType Directory -Force | Out-Null
287156

288-
# Clean previous files
289-
Get-ChildItem "$ProtoOut\*.cs" -ErrorAction SilentlyContinue | Remove-Item -Force
290-
291157
Write-Host "Generating C# protobuf classes..."
292158
& protoc --proto_path="$ProtoSrc" --csharp_out="$ProtoOut" --csharp_opt=file_extension=.g.cs "$ProtoSrc\pg_query.proto"
293-
294-
if ($LASTEXITCODE -ne 0) {
295-
Write-Error "❌ Protobuf generation failed"
296-
exit $LASTEXITCODE
297-
}
298-
299-
# Verify generated files
300-
if (-not (Test-Path "$ProtoOut\PgQuery.g.cs")) {
301-
Write-Error "❌ Expected protobuf files not generated"
302-
exit 1
303-
}
304-
159+
if ($LASTEXITCODE -ne 0) { Write-Error "❌ Protobuf generation failed"; exit $LASTEXITCODE }
160+
if (-not (Test-Path "$ProtoOut\PgQuery.g.cs")) { Write-Error "❌ Expected protobuf files not generated"; exit 1 }
305161
Write-Host "✅ Protobuf generation completed" -ForegroundColor Green
306162
}
307163

308-
# Step 5: Build .NET project
164+
# Step 5: Build and Test .NET project
309165
if (-not $SkipBuild) {
310-
Write-Host "🔨 Building .NET project..." -ForegroundColor Yellow
166+
Write-Host "🔨 Building .NET project for runtime $TargetRid..." -ForegroundColor Yellow
311167

312-
& dotnet build "src\GrepSQL\GrepSQL.csproj" `
168+
# Build the solution specifying the runtime. This ensures all projects are built
169+
# with the correct context for finding native dependencies.
170+
& dotnet build `
313171
--configuration $Configuration `
314-
--verbosity minimal `
315-
-p:Platform="Any CPU"
316-
if ($LASTEXITCODE -ne 0) {
317-
Write-Error "❌ Build failed"
318-
exit $LASTEXITCODE
319-
}
172+
--runtime $TargetRid
173+
if ($LASTEXITCODE -ne 0) { Write-Error "❌ Build failed"; exit $LASTEXITCODE }
320174

321175
Write-Host "✅ Build completed successfully" -ForegroundColor Green
322176

323-
# Run tests if they exist
324177
if (Test-Path "tests\GrepSQL.Tests.csproj") {
325-
Write-Host "🧪 Running tests..." -ForegroundColor Yellow
326-
& dotnet test --configuration $Configuration --verbosity minimal
178+
Write-Host "🧪 Running tests for runtime $TargetRid..." -ForegroundColor Yellow
179+
# The --runtime flag is the critical fix.
180+
# --no-build is a best practice to ensure we test what was just built.
181+
& dotnet test "tests\GrepSQL.Tests.csproj" `
182+
--configuration $Configuration `
183+
--runtime $TargetRid `
184+
--no-build `
185+
--verbosity normal
327186
if ($LASTEXITCODE -ne 0) {
328-
Write-Warning "⚠️ Tests failed"
187+
Write-Warning "⚠️ Tests failed. Please review the output."
188+
exit $LASTEXITCODE # Exit on test failure to fail the CI job
329189
}
330190
}
331191

332-
# Create NuGet package
333192
Write-Host "📦 Creating NuGet package..." -ForegroundColor Yellow
334193
New-Item -Path "artifacts" -ItemType Directory -Force | Out-Null
335194
& dotnet pack "src\GrepSQL\GrepSQL.csproj" `
336195
--configuration $Configuration `
337-
--output "artifacts" `
338-
-p:Platform="Any CPU"
196+
--output "artifacts"
339197
}
340198

341199
Write-Host ""
342-
Write-Host "🎉 Build completed successfully!" -ForegroundColor Green
343-
Write-Host ""
344-
Write-Host "📊 Build Summary:" -ForegroundColor Cyan
345-
Write-Host " Target RID: $TargetRid"
346-
Write-Host " Configuration: $Configuration"
347-
348-
if (Test-Path "runtimes\$TargetRid\native") {
349-
Write-Host " Generated Libraries:"
350-
Get-ChildItem "runtimes\$TargetRid\native" | ForEach-Object { Write-Host " $($_.Name)" }
351-
}
352-
353-
if (Test-Path "src\GrepSQL\AST\Generated") {
354-
Write-Host " Generated Protobuf Files:"
355-
Get-ChildItem "src\GrepSQL\AST\Generated\*.cs" | ForEach-Object { Write-Host " $($_.Name)" }
356-
}
357-
358-
if (Test-Path "artifacts") {
359-
Write-Host " NuGet Packages:"
360-
Get-ChildItem "artifacts\*.nupkg" | ForEach-Object { Write-Host " $($_.Name)" }
361-
}
200+
Write-Host "🎉 Build process completed successfully!" -ForegroundColor Green

0 commit comments

Comments
 (0)