# Builds the so-novel engine jar (from the submodule) and the tool wrapper classes. # Run once after clone / submodule update: pwsh tools\build.ps1 param( [switch]$Force, # rebuild so-novel even if runtime\app.jar exists [switch]$RefreshRules # re-copy bundle\rules over runtime\rules ) $ErrorActionPreference = 'Stop' . (Join-Path $PSScriptRoot 'lib.ps1') $p = Get-ToolPaths Write-Host "[build] project root : $($p.Root)" # ---------------------------------------------------------------- 1. JDK 21 $jdk = Find-Jdk21 -AllowDownload if (-not $jdk) { throw 'No JDK 21 available and download failed. Set EBOOK_NOVEL_JAVA_HOME.' } Write-Host "[build] JDK 21 : $jdk" $javac = Join-Path $jdk 'bin\javac.exe' if (-not (Test-Path $javac)) { throw "javac not found in $jdk (a JRE is not enough)" } # ---------------------------------------------------------------- 2. so-novel app.jar New-Item -ItemType Directory -Force $p.Runtime | Out-Null if ($Force -or -not (Test-Path $p.AppJar)) { if (-not (Test-Path (Join-Path $p.Vendor 'pom.xml'))) { throw 'vendor/so-novel is empty. Run: git submodule update --init --recursive' } $mvn = Get-Command mvn -ErrorAction SilentlyContinue if (-not $mvn) { throw 'Maven (mvn) is required to build so-novel. Install Maven or use a prebuilt app.jar.' } Write-Host '[build] mvn package so-novel ...' -ForegroundColor Cyan # so-novel 用 x86_64 激活 javet 原生库 profile,而 Windows JDK 报的是 amd64, # 自动激活会失效(导致 JS 规则的书源全部 "Javet library ... not found"),这里显式指定。 $platformProfile = switch -Regex ("$([System.Runtime.InteropServices.RuntimeInformation]::OSDescription)|$([System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture)") { 'Windows.*X64' { 'windows-x64' } 'Linux.*X64' { 'linux-x64' } 'Linux.*Arm64' { 'linux-arm64' } 'OSX|Darwin.*X64' { 'macos-x64' } 'OSX|Darwin.*Arm64' { 'macos-arm64' } default { $null } } if ($platformProfile) { Write-Host "[build] javet profile: $platformProfile" -ForegroundColor Cyan } else { Write-Warning 'Unknown platform, javet native library may be missing (JS-based rules will fail).' } $previousJavaHome = $env:JAVA_HOME $previousPath = $env:PATH try { $env:JAVA_HOME = $jdk $env:PATH = (Join-Path $jdk 'bin') + ';' + $previousPath Push-Location $p.Vendor try { $mvnArgs = @('-B', '-DskipTests', '-Dlaunch4j.skip=true') if ($platformProfile) { $mvnArgs += @('-P', $platformProfile) } $mvnArgs += @('clean', 'package') & $mvn.Source @mvnArgs if ($LASTEXITCODE -ne 0) { throw "mvn package failed with exit code $LASTEXITCODE" } } finally { Pop-Location } } finally { $env:JAVA_HOME = $previousJavaHome $env:PATH = $previousPath } $built = Join-Path $p.Vendor 'target\app-jar-with-dependencies.jar' if (-not (Test-Path $built)) { $built = Join-Path $p.Vendor 'target\app.jar' } if (-not (Test-Path $built)) { throw 'so-novel build produced no jar in target/' } Copy-Item $built $p.AppJar -Force Write-Host "[build] app.jar : $($p.AppJar) ($([math]::Round((Get-Item $p.AppJar).Length / 1MB, 1)) MB)" } else { Write-Host "[build] app.jar : up to date ($([math]::Round((Get-Item $p.AppJar).Length / 1MB, 1)) MB)" } # ---------------------------------------------------------------- 3. rule bundles New-Item -ItemType Directory -Force $p.Rules | Out-Null $sourceRules = Join-Path $p.Vendor 'bundle\rules' foreach ($file in (Get-ChildItem $sourceRules -Filter '*.json*' -File)) { $target = Join-Path $p.Rules $file.Name if ($RefreshRules -or -not (Test-Path $target)) { Copy-Item $file.FullName $target -Force } } Write-Host "[build] rules : $((Get-ChildItem $p.Rules -File).Count) files in $($p.Rules)" # ---------------------------------------------------------------- 4. tool classes if (Test-Path $p.Classes) { Remove-Item $p.Classes -Recurse -Force } New-Item -ItemType Directory -Force $p.Classes | Out-Null $sources = @(Get-ChildItem (Join-Path $p.Tools 'src') -Filter '*.java' -Recurse | ForEach-Object { $_.FullName }) Write-Host '[build] javac : tool wrapper ...' -ForegroundColor Cyan & $javac '-encoding' 'UTF-8' '--release' '21' '-cp' $p.AppJar '-d' $p.Classes @sources if ($LASTEXITCODE -ne 0) { throw "javac failed with exit code $LASTEXITCODE" } # Optional single-file tool jar (a plain classes dir works too; JBR has no jar.exe). $jarTool = Find-JarTool if ($jarTool) { & $jarTool '--create' '--file' $p.ToolJar '-C' $p.Classes '.' if ($LASTEXITCODE -ne 0) { Write-Warning 'jar packaging failed; the classes directory will be used instead.' } } # ---------------------------------------------------------------- 5. runtime config New-Item -ItemType Directory -Force $p.Books | Out-Null if ($Force -or -not (Test-Path $p.Config)) { $template = Get-Content (Join-Path $p.Tools 'config.ini.template') -Raw $ini = $template.Replace('@BOOKS@', ($p.Books -replace '\\', '/')) $ini = $ini.Replace('@RULES@', ((Join-Path $p.Rules 'main.json') -replace '\\', '/')) [System.IO.File]::WriteAllText($p.Config, $ini, (New-Object System.Text.UTF8Encoding($false))) Write-Host "[build] config.ini : $($p.Config)" } else { Write-Host "[build] config.ini : kept existing ($($p.Config))" } Write-Host '' Write-Host 'Build finished. Try: pwsh bin\novel.ps1 sources' -ForegroundColor Green