mirror of
https://gitflic.ru/project/openide/openide.git
synced 2025-12-15 02:59:33 +07:00
[build scripts] upgrading NSIS; using native compiler builds for all platforms
GitOrigin-RevId: 2d5f3e243d1b58d6b9b27c96ada9f59bce8e4f63
This commit is contained in:
committed by
intellij-monorepo-bot
parent
ad7dc482f3
commit
3b8e9b6693
@@ -5,7 +5,7 @@ gradleApiVersion=8.14
|
||||
gradleTAPI.jacksonCoreVersion=2.17.2
|
||||
jdkBuild=17.0.15b1381.5
|
||||
launcherBuild=252.16037
|
||||
nsisBuild=1
|
||||
nsisBuild=3.11
|
||||
restarterBuild=243.6005
|
||||
runtimeBuild=21.0.7b1021.38
|
||||
snapDockerImage=registry.jetbrains.team/p/ij/docker-hub/jetbrains/snapcraft@sha256:0059496b7a941e27937bc523621a336bddc1327de8dcd03f6b0bd0b57892ce43
|
||||
|
||||
@@ -1,11 +1,19 @@
|
||||
### Upgrading NSIS to a newer version
|
||||
|
||||
The NSIS.zip archive contains both Windows and Linux binaries, so in order to upgrade NSIS, one has to download the former,
|
||||
compile the latter, and pack both together. **Note**: please make sure all archives are of the same version.
|
||||
The NSIS.zip archive contains binaries for all supported platforms, so to upgrade NSIS, one has to download packages,
|
||||
compile the binaries, get required plugins, and pack everything together.
|
||||
|
||||
##### [Building](https://documentation.help/NSIS/SectionG.3.html) NSIS compiler on Linux
|
||||
##### Downloading
|
||||
|
||||
1. Install [SCons](https://scons.org) (standalone package is enough).
|
||||
1. Go to the [download site](https://sourceforge.net/projects/nsis/files/) and download
|
||||
`nsis-VERSION.zip`, `nsis-VERSION-strlen_8192.zip`, and `nsis-VERSION-src.tar.bz2` archives.
|
||||
2. Unpack the `nsis-VERSION.zip` archive and rename the top-level directory to 'NSIS'.
|
||||
3. Delete unneeded stuff (`Docs`, `Examples`, `makensisw.exe`, `NSIS.*`, `Plugins/x86-ansi`).
|
||||
4. Unpack the "strlen_8192" archive into the 'NSIS' directory (overwrite existing files).
|
||||
|
||||
##### [Building](https://documentation.help/NSIS/SectionG.3.html) NSIS compiler on Linux/macOS
|
||||
|
||||
1. Install [SCons](https://scons.org) (standalone package is enough) and build dependencies (gcc/g++, zlib-dev).
|
||||
2. Unpack NSIS source archive and `cd` into that directory.
|
||||
3. Build:
|
||||
```
|
||||
@@ -13,21 +21,24 @@ compile the latter, and pack both together. **Note**: please make sure all archi
|
||||
SKIPSTUBS=all SKIPPLUGINS=all SKIPUTILS=all SKIPMISC=all NSIS_CONFIG_CONST_DATA_PATH=no NSIS_MAX_STRLEN=8192 PREFIX=. \
|
||||
install-compiler
|
||||
```
|
||||
The resulting binary ('makensis') is in the current directory.
|
||||
The resulting binary (`makensis`) is in the current directory; rename them according to the platform conventions
|
||||
(`makensis-(mac|linux)-(amd64|aarch64)`).
|
||||
|
||||
##### Preparing the combined archive
|
||||
|
||||
1. [Download](https://sourceforge.net/projects/nsis/files/) and unpack zipped NSIS installation.
|
||||
2. Rename NSIS top-level directory into 'NSIS' and drop unneeded stuff ('Docs', 'Examples', 'makensisw.exe', 'NSIS.*', 'Plugins/x86-ansi').
|
||||
3. Download "strlen_8192" archive and unpack it into the 'NSIS' directory (overwrite existing files).
|
||||
4. Copy compiled Linux binary into 'NSIS/Bin' directory.
|
||||
5. From the old NSIS.zip archive, copy the following files into corresponding subdirectories of the 'NSIS' directory:
|
||||
- 'Include/UAC.nsh'
|
||||
- 'Plugins/x86-unicode/AccessControl.dll'
|
||||
- 'Plugins/x86-unicode/ExecDos.dll'
|
||||
- 'Plugins/x86-unicode/INetC.dll'
|
||||
- 'Plugins/x86-unicode/ShellLink.dll'
|
||||
- 'Plugins/x86-unicode/UAC.dll'
|
||||
6. Zip the 'NSIS' directory.
|
||||
7. Upload to https://jetbrains.team/p/ij/packages/files/intellij-build-dependencies/org/jetbrains/intellij/deps/nsis/.
|
||||
8. Update the version of 'nsisBuild' in community/build/dependencies/dependencies.properties.
|
||||
1. Copy compiled binaries into `NSIS/Bin` directory.
|
||||
2. From the old NSIS.zip archive, copy the following plugin files into corresponding subdirectories of the 'NSIS' directory:
|
||||
- `Include/UAC.nsh`
|
||||
- `Plugins/x86-unicode/AccessControl.dll`
|
||||
- `Plugins/x86-unicode/ExecDos.dll`
|
||||
- `Plugins/x86-unicode/ShellLink.dll`
|
||||
- `Plugins/x86-unicode/UAC.dll`
|
||||
3. Zip the 'NSIS' directory.
|
||||
4. Upload to https://jetbrains.team/p/ij/packages/files/intellij-build-dependencies/org/jetbrains/intellij/deps/nsis/.
|
||||
5. Update the version of 'nsisBuild' in community/build/dependencies/dependencies.properties.
|
||||
|
||||
Plugin pages; for reference:
|
||||
- [UAC](https://nsis.sourceforge.io/UAC_plug-in)
|
||||
- [Access Control](https://nsis.sourceforge.io/AccessControl_plug-in)
|
||||
- [ExecDos](https://nsis.sourceforge.io/ExecDos_plug-in)
|
||||
- [ShellLink](https://nsis.sourceforge.io/ShellLink_plug-in)
|
||||
|
||||
@@ -1,16 +1,19 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.intellij.build.impl
|
||||
|
||||
import com.intellij.openapi.util.SystemInfoRt
|
||||
import com.intellij.openapi.util.io.FileUtilRt
|
||||
import com.intellij.openapi.util.io.NioFiles
|
||||
import com.intellij.util.io.Decompressor
|
||||
import io.opentelemetry.api.trace.Span
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.jetbrains.intellij.build.*
|
||||
import org.jetbrains.intellij.build.io.copyDir
|
||||
import org.jetbrains.intellij.build.io.deleteDir
|
||||
import org.jetbrains.intellij.build.BuildContext
|
||||
import org.jetbrains.intellij.build.BuildOptions
|
||||
import org.jetbrains.intellij.build.JvmArchitecture
|
||||
import org.jetbrains.intellij.build.OsFamily
|
||||
import org.jetbrains.intellij.build.WindowsDistributionCustomizer
|
||||
import org.jetbrains.intellij.build.downloadFileToCacheLocation
|
||||
import org.jetbrains.intellij.build.executeStep
|
||||
import org.jetbrains.intellij.build.io.runProcess
|
||||
import org.jetbrains.intellij.build.telemetry.TraceManager.spanBuilder
|
||||
import org.jetbrains.intellij.build.telemetry.use
|
||||
@@ -19,37 +22,40 @@ import java.nio.file.Path
|
||||
import java.nio.file.StandardCopyOption
|
||||
import java.nio.file.attribute.FileTime
|
||||
import java.util.concurrent.TimeUnit
|
||||
import kotlin.io.path.isDirectory
|
||||
import kotlin.io.path.isRegularFile
|
||||
import kotlin.io.path.setLastModifiedTime
|
||||
import kotlin.time.Duration.Companion.hours
|
||||
|
||||
@Suppress("SpellCheckingInspection")
|
||||
internal suspend fun buildNsisInstaller(winDistPath: Path,
|
||||
additionalDirectoryToInclude: Path,
|
||||
suffix: String,
|
||||
customizer: WindowsDistributionCustomizer,
|
||||
runtimeDir: Path,
|
||||
context: BuildContext): Path? {
|
||||
if (SystemInfoRt.isMac && !Docker.isAvailable) {
|
||||
Span.current().addEvent("Windows installer cannot be built on macOS without Docker")
|
||||
return null
|
||||
}
|
||||
|
||||
internal suspend fun buildNsisInstaller(
|
||||
winDistPath: Path,
|
||||
additionalDirectoryToInclude: Path,
|
||||
suffix: String,
|
||||
customizer: WindowsDistributionCustomizer,
|
||||
runtimeDir: Path,
|
||||
context: BuildContext
|
||||
): Path? {
|
||||
val communityHome = context.paths.communityHomeDir
|
||||
val outFileName = context.productProperties.getBaseArtifactName(context) + suffix
|
||||
Span.current().setAttribute(outFileName, outFileName)
|
||||
|
||||
val box = context.paths.tempDir.resolve("winInstaller$suffix")
|
||||
//noinspection SpellCheckingInspection
|
||||
val nsiConfDir = box.resolve("nsiconf")
|
||||
withContext(Dispatchers.IO) {
|
||||
Files.createDirectories(nsiConfDir)
|
||||
copyDir(context.paths.communityHomeDir.resolve("build/conf/nsis"), nsiConfDir)
|
||||
val box = context.paths.tempDir.resolve("winInstaller${suffix}")
|
||||
|
||||
if (!SystemInfoRt.isWindows) {
|
||||
val (nsisDir, nsisBin) = prepareNsis(context, box)
|
||||
|
||||
val nsiConfDir = box.resolve("nsi-conf")
|
||||
Files.createDirectories(nsiConfDir)
|
||||
NioFiles.copyRecursively(context.paths.communityHomeDir.resolve("build/conf/nsis"), nsiConfDir)
|
||||
|
||||
if (OsFamily.currentOs != OsFamily.WINDOWS) {
|
||||
val ideaNsiPath = nsiConfDir.resolve("idea.nsi")
|
||||
Files.writeString(ideaNsiPath, BuildUtils.replaceAll(text = Files.readString(ideaNsiPath),
|
||||
replacements = mapOf("\${IMAGES_LOCATION}\\" to "\${IMAGES_LOCATION}/"),
|
||||
marker = ""))
|
||||
Files.writeString(ideaNsiPath, BuildUtils.replaceAll(
|
||||
text = Files.readString(ideaNsiPath),
|
||||
replacements = mapOf($$"${IMAGES_LOCATION}\\" to $$"${IMAGES_LOCATION}/"),
|
||||
marker = "")
|
||||
)
|
||||
}
|
||||
|
||||
val generator = NsisFileListGenerator()
|
||||
@@ -60,7 +66,7 @@ internal suspend fun buildNsisInstaller(winDistPath: Path,
|
||||
generator.generateInstallerFile(nsiConfDir.resolve("idea_win.nsh"))
|
||||
generator.generateUninstallerFile(nsiConfDir.resolve("unidea_win.nsh"))
|
||||
|
||||
prepareConfigurationFiles(nsiConfDir = nsiConfDir, winDistPath = winDistPath, customizer = customizer, context = context)
|
||||
prepareConfigurationFiles(nsiConfDir, winDistPath, customizer, context)
|
||||
for (it in customizer.customNsiConfigurationFiles) {
|
||||
val file = Path.of(it)
|
||||
val copy = nsiConfDir.resolve(file.fileName)
|
||||
@@ -68,65 +74,46 @@ internal suspend fun buildNsisInstaller(winDistPath: Path,
|
||||
copy.setLastModifiedTime(FileTime.from(context.options.buildDateInSeconds, TimeUnit.SECONDS))
|
||||
}
|
||||
|
||||
// Log final nsi directory to make debugging easier
|
||||
val logDir = context.paths.buildOutputDir.resolve("log")
|
||||
val nsiLogDir = logDir.resolve("nsi$suffix")
|
||||
deleteDir(nsiLogDir)
|
||||
copyDir(nsiConfDir, nsiLogDir)
|
||||
val nsiLogDir = context.paths.buildOutputDir.resolve("log/nsi$suffix")
|
||||
NioFiles.deleteRecursively(nsiLogDir)
|
||||
NioFiles.copyRecursively(nsiConfDir, nsiLogDir)
|
||||
|
||||
val nsisZip = downloadFileToCacheLocation(
|
||||
url = "https://packages.jetbrains.team/files/p/ij/intellij-build-dependencies/org/jetbrains/intellij/deps/nsis/" +
|
||||
"NSIS-${context.dependenciesProperties.property("nsisBuild")}.zip",
|
||||
communityRoot = context.paths.communityHomeDirRoot,
|
||||
)
|
||||
Decompressor.Zip(nsisZip).withZipExtensions().extract(box)
|
||||
spanBuilder("run NSIS tool to build .exe installer for Windows").use {
|
||||
val timeout = 2.hours
|
||||
if (SystemInfoRt.isWindows) {
|
||||
if (OsFamily.currentOs == OsFamily.WINDOWS) {
|
||||
runProcess(
|
||||
args = listOf(
|
||||
"$box/NSIS/makensis.exe",
|
||||
nsisBin.toString(),
|
||||
"/V2",
|
||||
"/DCOMMUNITY_DIR=$communityHome",
|
||||
"/DCOMMUNITY_DIR=${communityHome}",
|
||||
"/DIPR=${customizer.associateIpr}",
|
||||
"/DOUT_DIR=${context.paths.artifactDir}",
|
||||
"/DOUT_FILE=$outFileName",
|
||||
"$box/nsiconf/idea.nsi",
|
||||
"/DOUT_FILE=${outFileName}",
|
||||
"${nsiConfDir}/idea.nsi",
|
||||
),
|
||||
workingDir = box,
|
||||
timeout = timeout,
|
||||
timeout
|
||||
)
|
||||
}
|
||||
else {
|
||||
val makeNsis = "$box/NSIS/Bin/makensis${if (JvmArchitecture.currentJvmArch == JvmArchitecture.x64) "" else "-${JvmArchitecture.currentJvmArch.fileSuffix}"}"
|
||||
NioFiles.setExecutable(Path.of(makeNsis))
|
||||
val args = if (SystemInfoRt.isMac) {
|
||||
arrayOf(
|
||||
"docker", "run", "--rm",
|
||||
"--volume=$communityHome:$communityHome:ro",
|
||||
"--volume=${context.paths.buildOutputDir}:${context.paths.buildOutputDir}",
|
||||
"--workdir=$box",
|
||||
"ubuntu:18.04"
|
||||
)
|
||||
}
|
||||
else emptyArray()
|
||||
runProcess(
|
||||
args = listOf(
|
||||
*args, makeNsis,
|
||||
nsisBin.toString(),
|
||||
"-V2",
|
||||
"-DCOMMUNITY_DIR=$communityHome",
|
||||
"-DCOMMUNITY_DIR=${communityHome}",
|
||||
"-DIPR=${customizer.associateIpr}",
|
||||
"-DOUT_DIR=${context.paths.artifactDir}",
|
||||
"-DOUT_FILE=$outFileName",
|
||||
"$box/nsiconf/idea.nsi",
|
||||
"-DOUT_FILE=${outFileName}",
|
||||
"${nsiConfDir}/idea.nsi",
|
||||
),
|
||||
workingDir = box,
|
||||
timeout = timeout,
|
||||
additionalEnvVariables = mapOf("NSISDIR" to "$box/NSIS"),
|
||||
timeout,
|
||||
additionalEnvVariables = mapOf("NSISDIR" to nsisDir.toString(), "LC_CTYPE" to "C.UTF-8"),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val installerFile = context.paths.artifactDir.resolve("$outFileName.exe")
|
||||
check(Files.exists(installerFile)) {
|
||||
"Windows installer wasn't created."
|
||||
@@ -138,48 +125,59 @@ internal suspend fun buildNsisInstaller(winDistPath: Path,
|
||||
return installerFile
|
||||
}
|
||||
|
||||
private fun prepareConfigurationFiles(nsiConfDir: Path,
|
||||
winDistPath: Path,
|
||||
customizer: WindowsDistributionCustomizer,
|
||||
context: BuildContext) {
|
||||
private suspend fun prepareNsis(context: BuildContext, tempDir: Path): Pair<Path, Path> {
|
||||
val nsisVersion = context.dependenciesProperties.property("nsisBuild")
|
||||
val nsisUrl = "https://packages.jetbrains.team/files/p/ij/intellij-build-dependencies/org/jetbrains/intellij/deps/nsis/NSIS-${nsisVersion}.zip"
|
||||
val nsisZip = downloadFileToCacheLocation(nsisUrl, context.paths.communityHomeDirRoot)
|
||||
Decompressor.Zip(nsisZip).withZipExtensions().extract(tempDir)
|
||||
val nsisDir = tempDir.resolve("NSIS")
|
||||
require(nsisDir.isDirectory()) { "'${nsisDir.fileName}' is missing from ${nsisUrl}" }
|
||||
val ext = if (OsFamily.currentOs == OsFamily.WINDOWS) ".exe" else "-${OsFamily.currentOs.dirName}-${JvmArchitecture.currentJvmArch.dirName}"
|
||||
@Suppress("SpellCheckingInspection") val nsisBin = nsisDir.resolve("Bin/makensis${ext}")
|
||||
require(nsisBin.isRegularFile()) { "'${nsisDir.fileName}' is missing" }
|
||||
NioFiles.setExecutable(nsisBin)
|
||||
return nsisDir to nsisBin
|
||||
}
|
||||
|
||||
private fun prepareConfigurationFiles(nsiConfDir: Path, winDistPath: Path, customizer: WindowsDistributionCustomizer, context: BuildContext) {
|
||||
val productProperties = context.productProperties
|
||||
Files.writeString(nsiConfDir.resolve("paths.nsi"), $$"""
|
||||
!define IMAGES_LOCATION "$${FileUtilRt.toSystemDependentName(customizer.installerImagesPath!!)}"
|
||||
!define PRODUCT_PROPERTIES_FILE "$${FileUtilRt.toSystemDependentName("$winDistPath/bin/idea.properties")}"
|
||||
!define PRODUCT_VM_OPTIONS_NAME $${productProperties.baseFileName}*.exe.vmoptions
|
||||
!define PRODUCT_VM_OPTIONS_FILE "$${FileUtilRt.toSystemDependentName("${winDistPath}/bin/")}${PRODUCT_VM_OPTIONS_NAME}"
|
||||
""".trimIndent())
|
||||
|
||||
Files.writeString(nsiConfDir.resolve("paths.nsi"), """
|
||||
!define IMAGES_LOCATION "${FileUtilRt.toSystemDependentName(customizer.installerImagesPath!!)}"
|
||||
!define PRODUCT_PROPERTIES_FILE "${FileUtilRt.toSystemDependentName("$winDistPath/bin/idea.properties")}"
|
||||
!define PRODUCT_VM_OPTIONS_NAME ${productProperties.baseFileName}*.exe.vmoptions
|
||||
!define PRODUCT_VM_OPTIONS_FILE "${FileUtilRt.toSystemDependentName("${winDistPath}/bin/")}${'$'}{PRODUCT_VM_OPTIONS_NAME}"
|
||||
""")
|
||||
|
||||
val fileAssociations = if (customizer.fileAssociations.isEmpty()) "NoAssociation"
|
||||
else customizer.fileAssociations.joinToString(separator = ",") { if (it.startsWith(".")) it else ".${it}" }
|
||||
val fileAssociations =
|
||||
if (customizer.fileAssociations.isEmpty()) "NoAssociation"
|
||||
else customizer.fileAssociations.joinToString(separator = ",") { if (it.startsWith(".")) it else ".${it}" }
|
||||
val appInfo = context.applicationInfo
|
||||
Files.writeString(nsiConfDir.resolve("strings.nsi"), """
|
||||
!define MANUFACTURER "${appInfo.shortCompanyName}"
|
||||
!define MUI_PRODUCT "${customizer.getFullNameIncludingEdition(appInfo)}"
|
||||
!define PRODUCT_FULL_NAME "${customizer.getFullNameIncludingEditionAndVendor(appInfo)}"
|
||||
!define PRODUCT_EXE_FILE "${productProperties.baseFileName}64.exe"
|
||||
!define PRODUCT_ICON_FILE "install.ico"
|
||||
!define PRODUCT_UNINST_ICON_FILE "uninstall.ico"
|
||||
!define PRODUCT_LOGO_FILE "logo.bmp"
|
||||
!define PRODUCT_HEADER_FILE "headerlogo.bmp"
|
||||
!define ASSOCIATION "$fileAssociations"
|
||||
!define UNINSTALL_WEB_PAGE "${customizer.getUninstallFeedbackPageUrl(appInfo) ?: "feedback_web_page"}"
|
||||
!define MANUFACTURER "${appInfo.shortCompanyName}"
|
||||
!define MUI_PRODUCT "${customizer.getFullNameIncludingEdition(appInfo)}"
|
||||
!define PRODUCT_FULL_NAME "${customizer.getFullNameIncludingEditionAndVendor(appInfo)}"
|
||||
!define PRODUCT_EXE_FILE "${productProperties.baseFileName}64.exe"
|
||||
!define PRODUCT_ICON_FILE "install.ico"
|
||||
!define PRODUCT_UNINST_ICON_FILE "uninstall.ico"
|
||||
!define PRODUCT_LOGO_FILE "logo.bmp"
|
||||
!define PRODUCT_HEADER_FILE "headerlogo.bmp"
|
||||
!define ASSOCIATION "$fileAssociations"
|
||||
!define UNINSTALL_WEB_PAGE "${customizer.getUninstallFeedbackPageUrl(appInfo) ?: "feedback_web_page"}"
|
||||
|
||||
; if SHOULD_SET_DEFAULT_INSTDIR != 0 then default installation directory will be directory where highest-numbered IDE build has been installed
|
||||
; set to 1 for release build
|
||||
!define SHOULD_SET_DEFAULT_INSTDIR "0"
|
||||
""".trimIndent())
|
||||
|
||||
; if SHOULD_SET_DEFAULT_INSTDIR != 0 then default installation directory will be directory where highest-numbered IDE build has been installed
|
||||
; set to 1 for release build
|
||||
!define SHOULD_SET_DEFAULT_INSTDIR "0"
|
||||
""")
|
||||
|
||||
val versionString = if (appInfo.isEAP) "\${VER_BUILD}" else "\${MUI_VERSION_MAJOR}.\${MUI_VERSION_MINOR}"
|
||||
val versionString = if (appInfo.isEAP) $$"${VER_BUILD}" else $$"${MUI_VERSION_MAJOR}.${MUI_VERSION_MINOR}"
|
||||
val installDirAndShortcutName = customizer.getNameForInstallDirAndDesktopShortcut(appInfo, context.buildNumber)
|
||||
Files.writeString(nsiConfDir.resolve("version.nsi"), """
|
||||
!define MUI_VERSION_MAJOR "${appInfo.majorVersion}"
|
||||
!define MUI_VERSION_MINOR "${appInfo.minorVersion}"
|
||||
|
||||
!define VER_BUILD ${context.buildNumber}
|
||||
!define INSTALL_DIR_AND_SHORTCUT_NAME "$installDirAndShortcutName"
|
||||
!define PRODUCT_WITH_VER "${"$"}{MUI_PRODUCT} $versionString"
|
||||
!define PRODUCT_PATHS_SELECTOR "${context.systemSelector}"
|
||||
""")
|
||||
Files.writeString(nsiConfDir.resolve("version.nsi"), $$"""
|
||||
!define MUI_VERSION_MAJOR "$${appInfo.majorVersion}"
|
||||
!define MUI_VERSION_MINOR "$${appInfo.minorVersion}"
|
||||
|
||||
!define VER_BUILD $${context.buildNumber}
|
||||
!define INSTALL_DIR_AND_SHORTCUT_NAME "$$installDirAndShortcutName"
|
||||
!define PRODUCT_WITH_VER "${MUI_PRODUCT} $$versionString"
|
||||
!define PRODUCT_PATHS_SELECTOR "$${context.systemSelector}"
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user