[build] Support disabling modules and targets

This commit is contained in:
Him188 2022-08-26 16:35:13 +08:00
parent fb3f39e328
commit f87c142a69
No known key found for this signature in database
GPG Key ID: BA439CDDCF652375
6 changed files with 266 additions and 76 deletions

View File

@ -45,6 +45,7 @@ plugins {
}
osDetector = osdetector
BuildSrcRootProjectHolder.value = rootProject
GpgSigner.setup(project)

View File

@ -35,6 +35,7 @@ val OS_NAME = System.getProperty("os.name").toLowerCase()
lateinit var osDetector: OsDetector
// aarch = arm
val OsDetector.isAarch
get() = osDetector.arch.run {
@ -76,21 +77,26 @@ enum class HostArch {
/// eg. "!a;!b" means to enable all targets but a or b
/// eg. "a;b;!other" means to disable all targets but a or b
val ENABLED_TARGETS by lazy {
System.getProperty(
"mirai.target",
if (IDEA_ACTIVE)
// "jvm;android;${HOST_KIND.targetName};!other"
"other" // we must enable all targets otherwise you won't be able to edit code for non-host targets
else
""
).split(';').toSet()
val targets = System.getProperty(
"mirai.target"
) ?: rootProject.getLocalProperty("projects.mirai-core.targets")
?: "others" // enable all by default
targets.split(';').toSet()
}
fun isTargetEnabled(name: String): Boolean {
val isNative = name in POSSIBLE_NATIVE_TARGETS
return when {
name in ENABLED_TARGETS -> true
"!$name" in ENABLED_TARGETS -> false
else -> "!other" !in ENABLED_TARGETS
name in ENABLED_TARGETS -> true // explicitly enabled
"!$name" in ENABLED_TARGETS -> false // explicitly disabled
"native" in ENABLED_TARGETS && isNative -> true // native targets explicitly enabled
"!native" in ENABLED_TARGETS && isNative -> false // native targets explicitly disabled
"!other" in ENABLED_TARGETS -> false // others disabled
else -> true
}
}
@ -130,6 +136,8 @@ val UNIX_LIKE_TARGETS by lazy { LINUX_TARGETS + MAC_TARGETS }
val NATIVE_TARGETS by lazy { UNIX_LIKE_TARGETS + WIN_TARGETS }
private val POSSIBLE_NATIVE_TARGETS by lazy { setOf("mingwX64", "macosX64", "macosArm64", "linuxX64") }
fun Project.configureJvmTargetsHierarchical() {
extensions.getByType(KotlinMultiplatformExtension::class.java).apply {
val commonMain by sourceSets.getting
@ -206,6 +214,8 @@ fun Project.configureJvmTargetsHierarchical() {
fun KotlinMultiplatformExtension.configureNativeTargetsHierarchical(
project: Project
) {
if (NATIVE_TARGETS.isEmpty()) return
val nativeMainSets = mutableListOf<KotlinSourceSet>()
val nativeTestSets = mutableListOf<KotlinSourceSet>()
val nativeTargets = mutableListOf<KotlinNativeTarget>()
@ -243,39 +253,41 @@ fun KotlinMultiplatformExtension.configureNativeTargetsHierarchical(
}
}
val unixMain by lazy {
this.sourceSets.maybeCreate("unixMain").apply {
dependsOn(nativeMain)
if (UNIX_LIKE_TARGETS.isNotEmpty()) {
val unixMain by lazy {
this.sourceSets.maybeCreate("unixMain").apply {
dependsOn(nativeMain)
}
}
}
val unixTest by lazy {
this.sourceSets.maybeCreate("unixTest").apply {
dependsOn(nativeTest)
val unixTest by lazy {
this.sourceSets.maybeCreate("unixTest").apply {
dependsOn(nativeTest)
}
}
}
val darwinMain by lazy {
this.sourceSets.maybeCreate("darwinMain").apply {
dependsOn(unixMain)
val darwinMain by lazy {
this.sourceSets.maybeCreate("darwinMain").apply {
dependsOn(unixMain)
}
}
}
val darwinTest by lazy {
this.sourceSets.maybeCreate("darwinTest").apply {
dependsOn(unixTest)
val darwinTest by lazy {
this.sourceSets.maybeCreate("darwinTest").apply {
dependsOn(unixTest)
}
}
}
presets.filter { it.name in MAC_TARGETS }.forEach { preset ->
addNativeTarget(preset).run {
compilations[MAIN_COMPILATION_NAME].kotlinSourceSets.forEach { it.dependsOn(darwinMain) }
compilations[TEST_COMPILATION_NAME].kotlinSourceSets.forEach { it.dependsOn(darwinTest) }
presets.filter { it.name in MAC_TARGETS }.forEach { preset ->
addNativeTarget(preset).run {
compilations[MAIN_COMPILATION_NAME].kotlinSourceSets.forEach { it.dependsOn(darwinMain) }
compilations[TEST_COMPILATION_NAME].kotlinSourceSets.forEach { it.dependsOn(darwinTest) }
}
}
}
presets.filter { it.name in LINUX_TARGETS }.forEach { preset ->
addNativeTarget(preset).run {
compilations[MAIN_COMPILATION_NAME].kotlinSourceSets.forEach { it.dependsOn(unixMain) }
compilations[TEST_COMPILATION_NAME].kotlinSourceSets.forEach { it.dependsOn(unixTest) }
presets.filter { it.name in LINUX_TARGETS }.forEach { preset ->
addNativeTarget(preset).run {
compilations[MAIN_COMPILATION_NAME].kotlinSourceSets.forEach { it.dependsOn(unixMain) }
compilations[TEST_COMPILATION_NAME].kotlinSourceSets.forEach { it.dependsOn(unixTest) }
}
}
}

View File

@ -0,0 +1,56 @@
/*
* Copyright 2019-2022 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
*
* https://github.com/mamoe/mirai/blob/dev/LICENSE
*/
import org.gradle.api.Project
import java.util.*
/*
* Copyright 2019-2022 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
*
* https://github.com/mamoe/mirai/blob/dev/LICENSE
*/
object BuildSrcRootProjectHolder {
lateinit var value: Project
}
val rootProject: Project get() = BuildSrcRootProjectHolder.value
private lateinit var localProperties: Properties
private fun Project.loadLocalPropertiesIfAbsent() {
if (::localProperties.isInitialized) return
localProperties = Properties().apply {
rootProject.projectDir.resolve("local.properties").bufferedReader().use {
load(it)
}
}
}
fun Project.getLocalProperty(name: String): String? {
loadLocalPropertiesIfAbsent()
return localProperties.getProperty(name)
}
fun Project.getLocalProperty(name: String, default: String): String {
return getLocalProperty(name) ?: default
}
fun Project.getLocalProperty(name: String, default: Int): Int {
return getLocalProperty(name)?.toInt() ?: default
}
fun Project.getLocalProperty(name: String, default: Boolean): Boolean {
return getLocalProperty(name)?.toBoolean() ?: default
}

View File

@ -0,0 +1,41 @@
# 构建
本文介绍如何构建 mirai 的各模块。
## 构建 JVM 目标项目
要构建只有 JVM 目标的项目(如 `mirai-console`,只需在项目根目录使用如下命令执行
Gradle 任务:
```shell
$ ./gradlew :mirai-console:assemble # 编译
$ ./gradlew :mirai-console:check # 测试
$ ./gradlew :mirai-console:build # 编译和测试
```
其中 `:mirai-console` 是目标项目的路径path
你也可以在 IDEA 等有 Gradle 支持的 IDE
中在通过侧边栏等方式选择项目的 `assemble` 等任务:
![](images/run-gradle-tasks-in-idea.png)
### 获得 mirai-console JAR
在项目根目录执行如下命令可以获得包含依赖的 mirai-console JAR。对于其他模块类似。
```shell
$ ./gradlew :mirai-console:shadowJar
```
## 构建多平台项目
core 是多平台项目。请参考 [构建 Core](BuildingCore.md)。
## 构建 IntelliJ 插件
可通过如下命令构建 IntelliJ 平台 IDE 的插件。构建成功的插件将可以在 `mirai-console/tools/intellij-plugin/build/distribution` 中找到。
```shell
$ ./graldew :mirai-console-intellij:buidlPlugin
```

View File

@ -75,6 +75,19 @@ mirai 等。
若一个修改适合发布为小版本更新mirai 会从 `dev`
中提取该修复到目标 `-release` 分支。
## 安装 JDK
需要安装 JDK 才能编译 mirai。mirai 主分支最新提交在如下环境测试可以编译:
| 操作系统 | JDK | 架构 |
|--------------|--------------------|---------|
| macOS 12.0.1 | AdoptOpenJDK 17 | aarch64 |
| macOS 12.0.1 | Amazon Corretto 11 | amd64 |
| Windows 10 | OpenJDK 17 | amd64 |
| Ubuntu 20.04 | AdoptOpenJDK 17 | amd64 |
若在其他环境下无法正常编译, 请尝试选择上述一个环境配置。
## `mirai-core` 术语
根据语境mirai-core 有时候可能指 `mirai-core`
@ -108,54 +121,75 @@ core 的源集结构如图所示:
<darwin targets>
```
| 发布平台名称 | 描述 |
|------------|------------------|
| jvm | JVM |
| android | Android (Dalvik) |
| mingwX64 | Windows x64 |
| macosX64 | macOS x64 |
| macosArm64 | macOS arm64 |
| linuxX64 | Linux x64 |
备注:
- common 包含全平台通用代码,绝大部分代码都位于 common
- jvmBase 包含针对 JVM 平台的通用代码;
- `<darwin targets>` 为 macOSiOSWatchOS 等 Apple 平台目标。
## 安装 JDK
## 开发提示
需要安装 JDK 才能编译 mirai。mirai 主分支最新提交在如下环境测试可以编译:
建议使用 IntelliJ IDEA 或 Android Studio并安装最新的 Kotlin 插件。
| 操作系统 | JDK | 架构 |
|--------------|--------------------|---------|
| macOS 12.0.1 | AdoptOpenJDK 17 | aarch64 |
| macOS 12.0.1 | Amazon Corretto 11 | amd64 |
| Windows 10 | OpenJDK 17 | amd64 |
| Ubuntu 20.04 | AdoptOpenJDK 17 | amd64 |
建议设置 IntelliJ 的内存为至少 6GB否则 IDE 可能会频繁冻结编辑器收集垃圾。(可在 `Help -> Edit Custom VM Options` 中添加 `-Xmx6000m`
若在其他环境下无法正常编译, 请尝试选择上述一个环境配置。
### 关闭部分项目以提升速度
## 构建 JVM 目标项目
你可以在项目根目录创建 `local.properties`,中按照如下配置,关闭部分项目来提升开发速度。
要构建只有 JVM 目标的项目(如 `mirai-console`,只需在项目根目录使用如下命令执行
Gradle 任务:
```shell
$ ./gradlew :mirai-console:assemble # 编译
$ ./gradlew :mirai-console:check # 测试
$ ./gradlew :mirai-console:build # 编译和测试
```properties
# 关闭 IntelliJ IDEA 插件模块
projects.mirai-console-intellij.enabled=false
# 关闭 Gradle 插件模块
projects.mirai-console-gradle.enabled=false
# 关闭 mirai 依赖测试模块
projects.mirai-deps-test.enabled=false
# 用其他模块的路径替换 module-path可关闭该模块
projects.module-path.enabled=false
# 特殊配置,关闭 mirai-console 后端,这同时也会关闭全部 console 相关的项目
projects.mirai-console.enabled=false
# 特殊配置,关闭 mirai-logging这会关闭所有日志转接模块
projects.mirai-logging.enabled=false
```
其中 `:mirai-console` 是目标项目的路径path
通常关闭 IDEA 插件和 Gradle 插件可以显著提高初始化速度IDEA 插件项目在初始化时需要下载 1G 左右编译依赖)。
你也可以在 IDEA 等有 Gradle 支持的 IDE
中在通过侧边栏等方式选择项目的 `assemble` 等任务:
### 关闭 core 的部分构建目标
![](images/run-gradle-tasks-in-idea.png)
可以在上述 `local.properties` 中,配置 `projects.mirai-core.targets=` 使用以下配置语法关闭部分构建目标。关闭后可以减轻 IDE 负担,也可以避免下载工具链而加快初始化速度。
### 获得 mirai-console JAR
所有目标默认都启用。
在项目根目录执行如下命令可以获得包含依赖的 mirai-console JAR。对于其他模块类似。
**注意**,在关闭一个目标后,将无法编辑该目标的相关源集的源码。关闭 native 目标后也可能会影响 native 目标平台原生接口的数据类型。
因此若非主机性能太差或在 CI 机器运行,**不建议**关闭 native 目标。
```shell
$ ./gradlew :mirai-console:shadowJar
```
- `xxx`:显式启用 `xxx` 目标
- `!xxx`:显式禁用 `xxx` 目标
- `native`:显式启用所有 native 目标
- `!native`:禁用没有显式启用的所有 native 目标
- `others`:显式启用其他所有所有目标
- `!others`:禁用没有显式启用的所有目标
## 构建多平台项目
其中 xxx 表示构建目标名称。可用的目标名称有(区分大小写):`jvm`、`android`、`macosX64`、`macosArm64`、`mingwX64`、`linuxX64`
core 是多平台项目。请参考 [构建 Core](BuildingCore.md)。
示例(前两条目前等价):
- `!native;others` 指定禁用所有 native 目标,启用其他目标
- `jvm;android;!others` 指定启用 `jvm``android` 目标,禁用其他所有目标
- `jvm;macosX64;!others` 指定启用 `jvm``macosX64` 目标,禁用其他所有目标
## 构建
查看 [Building](Building.md)
## 寻找带解决的问题

View File

@ -1,3 +1,14 @@
/*
* Copyright 2019-2022 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
*
* https://github.com/mamoe/mirai/blob/dev/LICENSE
*/
import java.util.*
/*
* Copyright 2019-2022 Mamoe Technologies and contributors.
*
@ -20,12 +31,21 @@ pluginManagement {
rootProject.name = "mirai"
val localProperties = Properties().apply {
rootProject.projectDir.resolve("local.properties").bufferedReader().use {
load(it)
}
}
/**
* Projects included so far
*/
val allProjects = mutableListOf<ProjectDescriptor>()
fun includeProject(projectPath: String, dir: String? = null) {
if (!getLocalProperty("projects." + projectPath.removePrefix(":") + ".enabled", true)) return
include(projectPath)
if (dir != null) project(projectPath).projectDir = file(dir)
allProjects.add(project(projectPath))
@ -44,22 +64,29 @@ includeProject(":mirai-bom")
includeProject(":mirai-dokka")
includeProject(":mirai-deps-test")
includeProject(":mirai-logging-log4j2", "logging/mirai-logging-log4j2")
includeProject(":mirai-logging-slf4j", "logging/mirai-logging-slf4j")
includeProject(":mirai-logging-slf4j-simple", "logging/mirai-logging-slf4j-simple")
includeProject(":mirai-logging-slf4j-logback", "logging/mirai-logging-slf4j-logback")
if (getLocalProperty("projects.mirai-logging.enabled", true)) {
includeProject(":mirai-logging-log4j2", "logging/mirai-logging-log4j2")
includeProject(":mirai-logging-slf4j", "logging/mirai-logging-slf4j")
includeProject(":mirai-logging-slf4j-simple", "logging/mirai-logging-slf4j-simple")
includeProject(":mirai-logging-slf4j-logback", "logging/mirai-logging-slf4j-logback")
}
// mirai-core-api depends on this
includeConsoleProject(":mirai-console-compiler-annotations", "tools/compiler-annotations")
includeConsoleProject(":mirai-console", "backend/mirai-console")
includeConsoleProject(":mirai-console.codegen", "backend/codegen")
includeConsoleProject(":mirai-console-terminal", "frontend/mirai-console-terminal")
includeConsoleIntegrationTestProjects()
if (getLocalProperty("projects.mirai-console.enabled", true)) {
includeConsoleProject(":mirai-console", "backend/mirai-console")
includeConsoleProject(":mirai-console.codegen", "backend/codegen")
includeConsoleProject(":mirai-console-terminal", "frontend/mirai-console-terminal")
includeConsoleIntegrationTestProjects()
includeConsoleProject(":mirai-console-compiler-common", "tools/compiler-common")
includeConsoleProject(":mirai-console-intellij", "tools/intellij-plugin")
includeConsoleProject(":mirai-console-gradle", "tools/gradle-plugin")
} else {
// if mirai-console is disabled, disable all relevant projects
}
includeConsoleProject(":mirai-console-compiler-common", "tools/compiler-common")
includeConsoleProject(":mirai-console-intellij", "tools/intellij-plugin")
includeConsoleProject(":mirai-console-gradle", "tools/gradle-plugin")
//includeConsoleFrontendGraphical()
@ -133,4 +160,23 @@ fun includeConsoleIntegrationTestProjects() {
.listFiles()?.asSequence().orEmpty()
.filter { it.isDirectory }
.forEach { includeConsoleITPlugin(":mirai-console.integration-test:", it) }
}
fun getLocalProperty(name: String): String? {
return localProperties.getProperty(name)
}
fun getLocalProperty(name: String, default: String): String {
return localProperties.getProperty(name) ?: default
}
fun getLocalProperty(name: String, default: Int): Int {
return localProperties.getProperty(name)?.toInt() ?: default
}
fun getLocalProperty(name: String, default: Boolean): Boolean {
return localProperties.getProperty(name)?.toBoolean() ?: default
}