param( [ValidateRange(1, 32)] [int]$Jobs = 4, [switch]$Fresh ) $ErrorActionPreference = "Stop" . (Join-Path $PSScriptRoot "native_dep_versions.ps1") $Cmake = Join-Path $CmakeRoot "bin\cmake.exe" foreach ($required in @($Cmake, $Make, (Join-Path $MingwBin "gcc.exe"), (Join-Path $MingwBin "g++.exe"), $GrpcSource)) { if (-not (Test-Path -LiteralPath $required)) { throw "Required path not found: $required" } } function Enable-OldMingwProtobufCompatibility { $protobufRoot = Join-Path $GrpcSource "third_party\protobuf\src\google\protobuf" $utf8NoBom = New-Object System.Text.UTF8Encoding($false) function Set-TextFile([string]$path, [string]$content) { $current = [System.IO.File]::ReadAllText($path) if ($current -ne $content) { [System.IO.File]::WriteAllText($path, $content, $utf8NoBom) } } $portDef = Join-Path $protobufRoot "port_def.inc" $content = [System.IO.File]::ReadAllText($portDef) $newline = if ($content.Contains("`r`n")) { "`r`n" } else { "`n" } if (-not $content.Contains("PROTOBUF_MINGW_CONSTEXPR")) { $anchor = "#define PROTOBUF_CONSTINIT${newline}#endif${newline}" $macro = @( "#define PROTOBUF_CONSTINIT", "#endif", "", "#ifdef PROTOBUF_MINGW_CONSTEXPR", "#error PROTOBUF_MINGW_CONSTEXPR was previously defined", "#endif", "#if defined(__MINGW32__) && __GNUC__ < 8", "#define PROTOBUF_MINGW_CONSTEXPR", "#else", "#define PROTOBUF_MINGW_CONSTEXPR constexpr", "#endif", "" ) -join $newline if (-not $content.Contains($anchor)) { throw "Cannot patch Protobuf port_def.inc" } Set-TextFile $portDef $content.Replace($anchor, $macro) } $portUndef = Join-Path $protobufRoot "port_undef.inc" $content = [System.IO.File]::ReadAllText($portUndef) $newline = if ($content.Contains("`r`n")) { "`r`n" } else { "`n" } if (-not $content.Contains("#undef PROTOBUF_MINGW_CONSTEXPR")) { $anchor = "#undef PROTOBUF_CONSTINIT${newline}" if (-not $content.Contains($anchor)) { throw "Cannot patch Protobuf port_undef.inc" } Set-TextFile $portUndef $content.Replace( $anchor, "$anchor#undef PROTOBUF_MINGW_CONSTEXPR${newline}") } $mutexHeader = Join-Path $protobufRoot "stubs\mutex.h" $content = [System.IO.File]::ReadAllText($mutexHeader) $pattern = '(?s)(class GOOGLE_PROTOBUF_CAPABILITY\("mutex"\) PROTOBUF_EXPORT WrappedMutex \{\r?\n public:\r?\n).*?( void Lock)' $content = [regex]::Replace( $content, $pattern, '${1} PROTOBUF_MINGW_CONSTEXPR WrappedMutex() {}' + $newline + '${2}', 1) if (-not $content.Contains("PROTOBUF_MINGW_CONSTEXPR WrappedMutex")) { throw "Cannot patch Protobuf mutex.h" } Set-TextFile $mutexHeader $content $mapFieldHeader = Join-Path $protobufRoot "map_field.h" $content = [System.IO.File]::ReadAllText($mapFieldHeader) $content = [regex]::Replace( $content, '(?s)#if defined\(__MINGW32__\) && __GNUC__ < 8\r?\n#define PROTOBUF_MAP_FIELD_CONSTEXPR.*?#endif\r?\n\r?\n(?=class PROTOBUF_EXPORT MapFieldBase)', '') $content = $content.Replace("PROTOBUF_MAP_FIELD_CONSTEXPR", "PROTOBUF_MINGW_CONSTEXPR") $content = [regex]::Replace($content, '(?m)^#undef PROTOBUF_MINGW_CONSTEXPR\r?\n', '') $content = [regex]::Replace( $content, 'explicit constexpr (MapFieldBase|TypeDefinedMapFieldBase|MapField)\(ConstantInitialized', 'explicit PROTOBUF_MINGW_CONSTEXPR $1(ConstantInitialized') if (([regex]::Matches($content, "PROTOBUF_MINGW_CONSTEXPR (MapFieldBase|TypeDefinedMapFieldBase|MapField)\(")).Count -ne 3) { throw "Cannot patch Protobuf map_field.h" } Set-TextFile $mapFieldHeader $content $cppMessage = Join-Path $protobufRoot "compiler\cpp\cpp_message.cc" $content = [System.IO.File]::ReadAllText($cppMessage) $content = $content.Replace('explicit constexpr $classname$(', 'explicit PROTOBUF_MINGW_CONSTEXPR $classname$(') $content = $content.Replace('"explicit constexpr "', '"explicit PROTOBUF_MINGW_CONSTEXPR "') $content = $content.Replace('"constexpr $classname$::$classname$(', '"PROTOBUF_MINGW_CONSTEXPR $classname$::$classname$(') Set-TextFile $cppMessage $content $cppFile = Join-Path $protobufRoot "compiler\cpp\cpp_file.cc" $content = [System.IO.File]::ReadAllText($cppFile) $content = $content.Replace('" constexpr $1$()\n"', '" PROTOBUF_MINGW_CONSTEXPR $1$()\n"') Set-TextFile $cppFile $content foreach ($generatedRoot in @($GrpcSource, (Join-Path $GrpcBuild "gens"))) { if (-not (Test-Path -LiteralPath $generatedRoot)) { continue } foreach ($header in Get-ChildItem -LiteralPath $generatedRoot -Recurse -Filter "*.pb.h") { $content = [System.IO.File]::ReadAllText($header.FullName) $content = $content.Replace("explicit constexpr ", "explicit PROTOBUF_MINGW_CONSTEXPR ") Set-TextFile $header.FullName $content } foreach ($source in Get-ChildItem -LiteralPath $generatedRoot -Recurse -Filter "*.pb.cc") { $content = [System.IO.File]::ReadAllText($source.FullName) $content = [regex]::Replace( $content, '(?m)^constexpr (?=[A-Za-z_][A-Za-z0-9_]*::[A-Za-z_][A-Za-z0-9_]*\()', 'PROTOBUF_MINGW_CONSTEXPR ') $content = [regex]::Replace( $content, '(?m)^ constexpr (?=[A-Za-z_][A-Za-z0-9_]*DefaultTypeInternal\(\))', ' PROTOBUF_MINGW_CONSTEXPR ') Set-TextFile $source.FullName $content } } Write-Host "Applied Protobuf default-instance compatibility patch for MinGW GCC 7" } Enable-OldMingwProtobufCompatibility New-Item -ItemType Directory -Force $GrpcBuild, $GrpcInstall | Out-Null $env:PATH = "$MingwBin;$(Join-Path $CmakeRoot 'bin');$env:PATH" $GrpcSourceCmake = $GrpcSource.Replace("\", "/") $GrpcBuildCmake = $GrpcBuild.Replace("\", "/") $GrpcInstallCmake = $GrpcInstall.Replace("\", "/") $MingwBinCmake = $MingwBin.Replace("\", "/") $MakeCmake = $Make.Replace("\", "/") $configurePrefix = @() if ($Fresh -or -not (Test-Path -LiteralPath (Join-Path $GrpcBuild "CMakeCache.txt"))) { $configurePrefix += "--fresh" } & $Cmake @configurePrefix -S $GrpcSourceCmake -B $GrpcBuildCmake -G "MinGW Makefiles" ` "-DCMAKE_BUILD_TYPE=Release" ` "-DCMAKE_INSTALL_PREFIX=$GrpcInstallCmake" ` "-DCMAKE_C_COMPILER=$MingwBinCmake/gcc.exe" ` "-DCMAKE_CXX_COMPILER=$MingwBinCmake/g++.exe" ` "-DCMAKE_MAKE_PROGRAM=$MakeCmake" ` "-DCMAKE_POSITION_INDEPENDENT_CODE=ON" ` "-DBUILD_SHARED_LIBS=OFF" ` "-DBUILD_TESTING=OFF" ` "-DgRPC_INSTALL=ON" ` "-DgRPC_BUILD_TESTS=OFF" ` "-DgRPC_BUILD_CODEGEN=ON" ` "-DgRPC_BUILD_GRPC_CPP_PLUGIN=ON" ` "-DgRPC_BUILD_GRPC_CSHARP_PLUGIN=OFF" ` "-DgRPC_BUILD_GRPC_NODE_PLUGIN=OFF" ` "-DgRPC_BUILD_GRPC_OBJECTIVE_C_PLUGIN=OFF" ` "-DgRPC_BUILD_GRPC_PHP_PLUGIN=OFF" ` "-DgRPC_BUILD_GRPC_PYTHON_PLUGIN=OFF" ` "-DgRPC_BUILD_GRPC_RUBY_PLUGIN=OFF" ` "-DgRPC_ABSL_PROVIDER=module" ` "-DgRPC_CARES_PROVIDER=module" ` "-DgRPC_PROTOBUF_PROVIDER=module" ` "-DgRPC_RE2_PROVIDER=module" ` "-DgRPC_SSL_PROVIDER=module" ` "-DgRPC_ZLIB_PROVIDER=module" ` "-DRE2_BUILD_TESTING=OFF" ` "-Dprotobuf_BUILD_TESTS=OFF" ` "-Dprotobuf_BUILD_SHARED_LIBS=OFF" ` "-DABSL_ENABLE_INSTALL=ON" ` "-DCARES_STATIC=ON" ` "-DCARES_SHARED=OFF" ` "-DCARES_BUILD_TOOLS=OFF" ` "-DOPENSSL_NO_ASM=ON" if ($LASTEXITCODE -ne 0) { throw "gRPC configure failed" } & $Cmake --build $GrpcBuild --target install --parallel $Jobs if ($LASTEXITCODE -ne 0) { throw "gRPC build failed" } $Protoc = Join-Path $GrpcInstall "bin\protoc.exe" $GrpcPlugin = Join-Path $GrpcInstall "bin\grpc_cpp_plugin.exe" if (-not (Test-Path -LiteralPath $Protoc) -or -not (Test-Path -LiteralPath $GrpcPlugin)) { throw "gRPC build finished but protoc or grpc_cpp_plugin is missing" } Write-Host "gRPC and Protobuf installed to $GrpcInstall"