diff --git a/.gitignore b/.gitignore index 9b7bb83d3f4ce..d670b3fe0dbd0 100644 --- a/.gitignore +++ b/.gitignore @@ -39,3 +39,4 @@ __pycache__ # Don't ignore src files under build package !**/src/**/build +/jbdeps/android-sdk/linux/* \ No newline at end of file diff --git a/.run/All tests.run.xml b/.run/All tests.run.xml new file mode 100644 index 0000000000000..f2ba200dcd4b3 --- /dev/null +++ b/.run/All tests.run.xml @@ -0,0 +1,26 @@ + + + + + + + false + true + false + + + \ No newline at end of file diff --git a/.run/Compiler (Unit tests).run.xml b/.run/Compiler (Unit tests).run.xml new file mode 100644 index 0000000000000..0db94ad99a275 --- /dev/null +++ b/.run/Compiler (Unit tests).run.xml @@ -0,0 +1,23 @@ + + + + + + + false + true + false + + + \ No newline at end of file diff --git a/.run/Runtime (Android integration tests).run.xml b/.run/Runtime (Android integration tests).run.xml new file mode 100644 index 0000000000000..e43217e149bdb --- /dev/null +++ b/.run/Runtime (Android integration tests).run.xml @@ -0,0 +1,55 @@ + + + + + \ No newline at end of file diff --git a/.run/Runtime (Unit tests).run.xml b/.run/Runtime (Unit tests).run.xml new file mode 100644 index 0000000000000..569b2f1f77c31 --- /dev/null +++ b/.run/Runtime (Unit tests).run.xml @@ -0,0 +1,24 @@ + + + + + + + false + true + false + + + \ No newline at end of file diff --git a/README.md b/README.md index be89bdb816ab3..86492992bb22e 100644 --- a/README.md +++ b/README.md @@ -1,69 +1,35 @@ -# Android Jetpack +# Fork of https://github.com/androidx/androidx (androidx-main branch) to test Compose Compiler -[![Revved up by Develocity](https://img.shields.io/badge/Revved%20up%20by-Develocity-06A0CE?logo=Gradle&labelColor=02303A)](https://ge.androidx.dev) +TODO(igor.demin@jetbrains.com): we need to test Compose Compiler for JS and Native too -Jetpack is a suite of libraries, tools, and guidance to help developers write high-quality apps easier. These components help you follow best practices, free you from writing boilerplate code, and simplify complex tasks, so you can focus on the code you care about. +## Developing in IDE -Jetpack comprises the `androidx.*` package libraries, unbundled from the platform APIs. This means that it offers backward compatibility and is updated more frequently than the Android platform, making sure you always have access to the latest and greatest versions of the Jetpack components. +1. Download Android Studio version that is specified in [libs.versions.toml](gradle/libs.versions.toml#L11) -Our official AARs and JARs binaries are distributed through [Google Maven](https://maven.google.com). +2. Open the project in Android Studio -You can learn more about using it from [Android Jetpack landing page](https://developer.android.com/jetpack). +3. Make sure that you use OpenJDK 11 in `Project settings -> Project`, and have `Gradle JVM = Project SDK` in `Settings -> Build, Executions, Deployment -> Build Tools -> Gradle` -# Contribution Guide +4. Change Kotlin version in `gradle/libs.versions.toml` if needed (search for `kotlin = `) -For contributions via GitHub, see the [GitHub Contribution Guide](CONTRIBUTING.md). +5. Run `All tests`, `Compiler (Unit tests)`, `Runtime (Unit tests)` or `Runtime (Android integration tests)` to run tests. +If you don't see them, restart Android Studio (it seems a bug). -Note: The contributions workflow via GitHub is currently experimental - only contributions to the following projects are being accepted at this time: -* [Activity](activity) -* [AppCompat](appcompat) -* [Biometric](biometric) -* [Collection](collection) -* [Compose Compiler](compose/compiler) -* [Compose Runtime](compose/runtime) -* [Core](core) -* [DataStore](datastore) -* [Fragment](fragment) -* [Lifecycle](lifecycle) -* [Navigation](navigation) -* [Paging](paging) -* [Room](room) -* [WorkManager](work) +Notes: +- To run All tests you need a connected Android device or emulator (Android studio don't run it automatically) +- Compiler tests seems don't work on Windows -## Code Review Etiquette -When contributing to Jetpack, follow the [code review etiquette](code-review.md). +## Gradle commands -## Accepted Types of Contributions -* Bug fixes - needs a corresponding bug report in the [Android Issue Tracker](https://issuetracker.google.com/issues/new?component=192731&template=842428) -* Each bug fix is expected to come with tests -* Fixing spelling errors -* Updating documentation -* Adding new tests to the area that is not currently covered by tests -* New features to existing libraries if the feature request bug has been approved by an AndroidX team member. +1. Gradle command to build Compose Compiler: +``` +export COMPOSE_CUSTOM_VERSION=0.0.0-custom2 +./gradlew compose:compiler:compiler:publishMavenPublicationToLocalRepository +``` +The artifact `androidx.compose.compiler:compiler:0.0.0-custom2` will be in `~/.m2/repository/androidx/compose/compiler/compiler/0.0.0-custom2` -We **are not** currently accepting new modules. - -## Checking Out the Code - -Head over to the [onboarding docs](docs/onboarding.md) to learn more about getting set up and the -development workflow! - -### Continuous integration -[Our continuous integration system](https://ci.android.com/builds/branches/aosp-androidx-main/grid?) builds all in progress (and potentially unstable) libraries as new changes are merged. You can manually download these AARs and JARs for your experimentation. - -## Password and Contributor Agreement before making a change -Before uploading your first contribution, you will need setup a password and agree to the contribution agreement: - -Generate a HTTPS password: -https://android-review.googlesource.com/new-password - -Agree to the Google Contributor Licenses Agreement: -https://android-review.googlesource.com/settings/new-agreement - -## Getting reviewed -* After you run repo upload, open [r.android.com](http://r.android.com) -* Sign in into your account (or create one if you do not have one yet) -* Add an appropriate reviewer (use git log to find who did most modifications on the file you are fixing or check the OWNERS file in the project's directory) - -## Handling binary dependencies -AndroidX uses git to store all the binary Gradle dependencies. They are stored in `prebuilts/androidx/internal` and `prebuilts/androidx/external` directories in your checkout. All the dependencies in these directories are also available from `google()`, or `mavenCentral()`. We store copies of these dependencies to have hermetic builds. You can pull in [a new dependency using our importMaven tool](development/importMaven/README.md). +2. Gradle command to test Compose Runtime: +``` +./gradlew :compose:runtime:runtime:testDebugUnitTest :compose:runtime:runtime:integration-tests:connectedAndroidTest :compose:compiler:compiler-hosted:integration-tests:testDebugUnitTest +``` +It runs unit tests and Android tests (there should be a connected Android device or emulator) diff --git a/buildSrc/private/src/main/kotlin/androidx/build/AndroidXExtension.kt b/buildSrc/private/src/main/kotlin/androidx/build/AndroidXExtension.kt index bc564a21e30ed..931d719678a87 100644 --- a/buildSrc/private/src/main/kotlin/androidx/build/AndroidXExtension.kt +++ b/buildSrc/private/src/main/kotlin/androidx/build/AndroidXExtension.kt @@ -43,6 +43,9 @@ abstract class AndroidXExtension(val project: Project) : ExtensionAware, Android val listProjectsService: Provider + private val composeCustomVersion = project.providers.environmentVariable("COMPOSE_CUSTOM_VERSION") + private val composeCustomGroup = project.providers.environmentVariable("COMPOSE_CUSTOM_GROUP") + private val versionService: LibraryVersionsService val deviceTests = DeviceTests.register(project.extensions) @@ -186,12 +189,17 @@ abstract class AndroidXExtension(val project: Project) : ExtensionAware, Android return null } // convert parent project path to groupId - val groupIdText = - if (projectPath.startsWith(":external")) { - projectPath.replace(":external:", "") + val groupIdText = if (projectPath.startsWith(":external")) { + projectPath.replace(":external:", "") + } else { + "androidx.${parentPath.substring(1).replace(':', '.')}" + }.let { + if (it.contains("compose") && composeCustomGroup.isPresent) { + it.replace("androidx.compose", composeCustomGroup.get()) } else { - "androidx.${parentPath.substring(1).replace(':', '.')}" + it } + } // get the library group having that text val result = libraryGroupsByGroupId[groupIdText] diff --git a/buildSrc/private/src/main/kotlin/androidx/build/AndroidXImplPlugin.kt b/buildSrc/private/src/main/kotlin/androidx/build/AndroidXImplPlugin.kt index 722d2b3569706..e3b4186c43171 100644 --- a/buildSrc/private/src/main/kotlin/androidx/build/AndroidXImplPlugin.kt +++ b/buildSrc/private/src/main/kotlin/androidx/build/AndroidXImplPlugin.kt @@ -182,8 +182,8 @@ constructor(private val componentFactory: SoftwareComponentFactory) : Plugin { maybeRegisterFilterableTask() + val isJBFork = true // If we're running inside Studio, validate the Android Gradle Plugin version. val expectedAgpVersion = System.getenv("EXPECTED_AGP_VERSION") - if (properties.containsKey("android.injected.invoked.from.ide")) { + if (!isJBFork && properties.containsKey("android.injected.invoked.from.ide")) { if (expectedAgpVersion != ANDROID_GRADLE_PLUGIN_VERSION) { throw GradleException( """ diff --git a/buildSrc/public/src/main/kotlin/androidx/build/SdkHelper.kt b/buildSrc/public/src/main/kotlin/androidx/build/SdkHelper.kt index f056d5670fca3..aafeb95882d86 100644 --- a/buildSrc/public/src/main/kotlin/androidx/build/SdkHelper.kt +++ b/buildSrc/public/src/main/kotlin/androidx/build/SdkHelper.kt @@ -49,10 +49,8 @@ fun Project.getSdkDependency(): FileTree = /** Returns the root project's platform-specific SDK path as a file. */ fun Project.getSdkPath(): File { - if ( - rootProject.plugins.hasPlugin("AndroidXPlaygroundRootPlugin") || - System.getenv("COMPOSE_DESKTOP_GITHUB_BUILD") != null - ) { + val isJBFork = true + if (isJBFork) { // This is not full checkout, use local settings instead. // https://developer.android.com/studio/command-line/variables // check for local.properties first diff --git a/buildSrc/public/src/main/kotlin/androidx/build/SdkResourceGenerator.kt b/buildSrc/public/src/main/kotlin/androidx/build/SdkResourceGenerator.kt index 991a22c58618a..005156e8d3cad 100644 --- a/buildSrc/public/src/main/kotlin/androidx/build/SdkResourceGenerator.kt +++ b/buildSrc/public/src/main/kotlin/androidx/build/SdkResourceGenerator.kt @@ -124,6 +124,12 @@ abstract class SdkResourceGenerator : DefaultTask() { @JvmStatic fun generateForHostTest(project: Project) { + // We have this error on Windows: + // Could not create task ':compose:compiler:compiler:integration-tests:generateSdkResource'. + // > this and base files have different roots: ~\.m2\repository and ...\compose-jb\compose\frameworks\support\compose\compiler\compiler\integration-tests. + val os = System.getProperty("os.name").lowercase() + if (os.startsWith("win")) return + val provider = registerSdkResourceGeneratorTask(project) val extension = project.extensions.getByType() val testSources = extension.sourceSets.getByName("test") diff --git a/buildSrc/public/src/main/kotlin/androidx/build/Version.kt b/buildSrc/public/src/main/kotlin/androidx/build/Version.kt index 4b4a47306d556..6a9b0498a212d 100644 --- a/buildSrc/public/src/main/kotlin/androidx/build/Version.kt +++ b/buildSrc/public/src/main/kotlin/androidx/build/Version.kt @@ -75,7 +75,7 @@ data class Version(val major: Int, val minor: Int, val patch: Int, val extra: St private const val serialVersionUID = 345435634563L private val VERSION_FILE_REGEX = Pattern.compile("^(res-)?(.*).txt$") - private val VERSION_REGEX = Pattern.compile("^(\\d+)\\.(\\d+)\\.(\\d+)(-.+)?$") + private val VERSION_REGEX = Pattern.compile("^(\\d+)\\.(\\d+)\\.(\\d+)((?:\\.\\d+)?(?:-.+)?)?$") private fun checkedMatcher(versionString: String): Matcher { val matcher = VERSION_REGEX.matcher(versionString) diff --git a/buildSrc/repos.gradle b/buildSrc/repos.gradle index 297a520624902..8dafc107723f7 100644 --- a/buildSrc/repos.gradle +++ b/buildSrc/repos.gradle @@ -63,14 +63,28 @@ def addMavenRepositories(RepositoryHandler handler) { } } } - if (System.getenv("ALLOW_PUBLIC_REPOS") != null || System.getProperty("ALLOW_PUBLIC_REPOS") != null) { + def isJBFork = true + if (isJBFork) { + handler.maven { + url("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/dev/") + } + handler.mavenLocal() handler.mavenCentral() handler.google() handler.gradlePluginPortal() handler.maven { url("https://maven.pkg.jetbrains.space/public/p/compose/dev") } - handler.mavenLocal() + handler.maven { + url("https://maven.pkg.jetbrains.space/public/p/kotlinx-coroutines/maven") + } + // TODO(b/280646217): Remove after official release to gmaven. + handler.maven { + url("https://storage.googleapis.com/r8-releases/raw") + content { + includeModule("com.android.tools", "r8") + } + } } // Ordering appears to be important: b/229733266 def androidPluginRepoOverride = System.getenv("GRADLE_PLUGIN_REPO") diff --git a/buildSrc/settings.gradle b/buildSrc/settings.gradle index 68c85829b52c9..8c3c34f641bee 100644 --- a/buildSrc/settings.gradle +++ b/buildSrc/settings.gradle @@ -29,6 +29,7 @@ include ":imports:stableaidl-gradle-plugin" dependencyResolutionManagement { versionCatalogs { libs { + //from(files("../gradle/libs.versions.toml")) def agpOverride = System.getenv("GRADLE_PLUGIN_VERSION") if (agpOverride != null) { logger.warn("Using custom version ${agpOverride} of AGP due to GRADLE_PLUGIN_VERSION being set.") diff --git a/buildSrc/settingsScripts/project-dependency-graph.groovy b/buildSrc/settingsScripts/project-dependency-graph.groovy index a59f5f1f15d59..d89964c36993d 100644 --- a/buildSrc/settingsScripts/project-dependency-graph.groovy +++ b/buildSrc/settingsScripts/project-dependency-graph.groovy @@ -221,7 +221,7 @@ class ProjectDependencyGraph { // fixed. // This option is supported so that development/simplify_build_failure.sh can try // deleting entire projects at once to identify the cause of a build failure - if (System.getenv("ALLOW_MISSING_PROJECTS") == null) { + if (System.getenv("ALLOW_MISSING_PROJECTS") == null && false) { throw new Exception("Path " + buildGradle + " does not exist;" + "cannot include project " + projectPath + " ($projectDir)") } diff --git a/buildSrc/shared.gradle b/buildSrc/shared.gradle index b135cf6f03237..616bb4c438f1d 100644 --- a/buildSrc/shared.gradle +++ b/buildSrc/shared.gradle @@ -36,7 +36,7 @@ tasks.withType(KotlinCompile).configureEach { kotlinOptions { jvmTarget = "17" freeCompilerArgs += [ - "-Werror", + //"-Werror", "-Xskip-metadata-version-check" ] languageVersion = "1.8" diff --git a/compose/compiler/compiler-hosted/build.gradle b/compose/compiler/compiler-hosted/build.gradle index dfa7c90fdd154..98cdfd598c936 100644 --- a/compose/compiler/compiler-hosted/build.gradle +++ b/compose/compiler/compiler-hosted/build.gradle @@ -39,6 +39,9 @@ dependencies { } tasks.withType(KotlinCompile).configureEach { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + kotlinOptions { jvmTarget = "1.8" freeCompilerArgs = [ diff --git a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeIrGenerationExtension.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeIrGenerationExtension.kt index 9ffd47dce893d..113d6acd8aa22 100644 --- a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeIrGenerationExtension.kt +++ b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposeIrGenerationExtension.kt @@ -19,6 +19,7 @@ package androidx.compose.compiler.plugins.kotlin import androidx.compose.compiler.plugins.kotlin.analysis.FqNameMatcher import androidx.compose.compiler.plugins.kotlin.analysis.StabilityInferencer import androidx.compose.compiler.plugins.kotlin.lower.ClassStabilityTransformer +import androidx.compose.compiler.plugins.kotlin.lower.ClassStabilityInferredCollection import androidx.compose.compiler.plugins.kotlin.lower.ComposableFunInterfaceLowering import androidx.compose.compiler.plugins.kotlin.lower.ComposableFunctionBodyTransformer import androidx.compose.compiler.plugins.kotlin.lower.ComposableLambdaAnnotator @@ -36,6 +37,8 @@ import androidx.compose.compiler.plugins.kotlin.lower.WrapJsComposableLambdaLowe import androidx.compose.compiler.plugins.kotlin.lower.decoys.CreateDecoysTransformer import androidx.compose.compiler.plugins.kotlin.lower.decoys.RecordDecoySignaturesTransformer import androidx.compose.compiler.plugins.kotlin.lower.decoys.SubstituteDecoyCallsTransformer +import androidx.compose.compiler.plugins.kotlin.lower.hiddenfromobjc.AddHiddenFromObjCLowering +import androidx.compose.compiler.plugins.kotlin.lower.hiddenfromobjc.HideFromObjCDeclarationsSet import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext import org.jetbrains.kotlin.backend.common.serialization.DeclarationTable @@ -46,7 +49,9 @@ import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsManglerIr import org.jetbrains.kotlin.ir.declarations.IrModuleFragment import org.jetbrains.kotlin.ir.visitors.acceptVoid import org.jetbrains.kotlin.platform.isJs +import org.jetbrains.kotlin.platform.isWasm import org.jetbrains.kotlin.platform.jvm.isJvm +import org.jetbrains.kotlin.platform.konan.isNative class ComposeIrGenerationExtension( @Suppress("unused") private val liveLiteralsEnabled: Boolean = false, @@ -62,7 +67,9 @@ class ComposeIrGenerationExtension( private val useK2: Boolean = false, private val strongSkippingEnabled: Boolean = false, private val stableTypeMatchers: Set = emptySet(), - private val moduleMetricsFactory: ((StabilityInferencer) -> ModuleMetrics)? = null + private val moduleMetricsFactory: ((StabilityInferencer) -> ModuleMetrics)? = null, + private val hideFromObjCDeclarationsSet: HideFromObjCDeclarationsSet? = null, + private val classStabilityInferredCollection: ClassStabilityInferredCollection? = null ) : IrGenerationExtension { var metrics: ModuleMetrics = EmptyModuleMetrics private set @@ -99,12 +106,25 @@ class ComposeIrGenerationExtension( } } + if (pluginContext.platform.isNative() && hideFromObjCDeclarationsSet != null) { + AddHiddenFromObjCLowering( + pluginContext, + symbolRemapper, + metrics, + hideFromObjCDeclarationsSet, + stabilityInferencer + ).lower(moduleFragment) + } + ClassStabilityTransformer( useK2, pluginContext, symbolRemapper, metrics, - stabilityInferencer + stabilityInferencer, + classStabilityInferredCollection = classStabilityInferredCollection?.takeIf { + pluginContext.platform?.isJvm() == false + } ).lower(moduleFragment) LiveLiteralTransformer( @@ -144,6 +164,7 @@ class ComposeIrGenerationExtension( val mangler = when { pluginContext.platform.isJs() -> JsManglerIr + pluginContext.platform.isWasm() -> JsManglerIr else -> null } @@ -152,6 +173,10 @@ class ComposeIrGenerationExtension( PublicIdSignatureComputer(mangler!!), DeclarationTable(JsGlobalDeclarationTable(pluginContext.irBuiltIns)) ) + pluginContext.platform.isWasm() -> IdSignatureSerializer( + PublicIdSignatureComputer(mangler!!), + DeclarationTable(JsGlobalDeclarationTable(pluginContext.irBuiltIns)) + ) else -> null } if (decoysEnabled) { @@ -233,7 +258,7 @@ class ComposeIrGenerationExtension( ).lower(moduleFragment) } - if (pluginContext.platform.isJs()) { + if (pluginContext.platform.isWasm() || pluginContext.platform.isJs()) { WrapJsComposableLambdaLowering( pluginContext, symbolRemapper, diff --git a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposePlugin.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposePlugin.kt index 9911b1ba626af..cc6359f14e3d9 100644 --- a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposePlugin.kt +++ b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/ComposePlugin.kt @@ -25,6 +25,9 @@ import androidx.compose.compiler.plugins.kotlin.k1.ComposeDiagnosticSuppressor import androidx.compose.compiler.plugins.kotlin.k1.ComposeTypeResolutionInterceptorExtension import androidx.compose.compiler.plugins.kotlin.k2.ComposeFirExtensionRegistrar import androidx.compose.compiler.plugins.kotlin.lower.ClassStabilityFieldSerializationPlugin +import androidx.compose.compiler.plugins.kotlin.lower.ClassStabilityInferredCollection +import androidx.compose.compiler.plugins.kotlin.lower.hiddenfromobjc.AddHiddenFromObjCSerializationPlugin +import androidx.compose.compiler.plugins.kotlin.lower.hiddenfromobjc.HideFromObjCDeclarationsSet import com.intellij.mock.MockProject import com.intellij.openapi.project.Project import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension @@ -77,6 +80,8 @@ object ComposeConfiguration { ) val TRACE_MARKERS_ENABLED_KEY = CompilerConfigurationKey("Include composition trace markers in generated code") + val HIDE_DECLARATION_FROM_OBJC_ENABLED_KEY = + CompilerConfigurationKey("Add HiddenFromObjC annotation to declarations") } @OptIn(ExperimentalCompilerApi::class) @@ -147,6 +152,13 @@ class ComposeCommandLineProcessor : CommandLineProcessor { required = false, allowMultipleOccurrences = false ) + val HIDE_DECLARATION_FROM_OBJC_OPTION = CliOption( + "hideFromObjC", + "", + "Add HiddenFromObjC annotation to Composable declarations", + required = false, + allowMultipleOccurrences = false + ) val STRONG_SKIPPING_OPTION = CliOption( "experimentalStrongSkipping", "", @@ -183,7 +195,8 @@ class ComposeCommandLineProcessor : CommandLineProcessor { DECOYS_ENABLED_OPTION, STRONG_SKIPPING_OPTION, STABLE_CONFIG_PATH_OPTION, - TRACE_MARKERS_OPTION + TRACE_MARKERS_OPTION, + HIDE_DECLARATION_FROM_OBJC_OPTION, ) override fun processOption( @@ -227,6 +240,10 @@ class ComposeCommandLineProcessor : CommandLineProcessor { ComposeConfiguration.DECOYS_ENABLED_KEY, value == "true" ) + HIDE_DECLARATION_FROM_OBJC_OPTION -> configuration.put( + ComposeConfiguration.HIDE_DECLARATION_FROM_OBJC_ENABLED_KEY, + value == "true" + ) STRONG_SKIPPING_OPTION -> configuration.put( ComposeConfiguration.STRONG_SKIPPING_ENABLED_KEY, value == "true" @@ -255,10 +272,24 @@ class ComposePluginRegistrar : org.jetbrains.kotlin.compiler.plugin.ComponentReg configuration: CompilerConfiguration ) { if (checkCompilerVersion(configuration)) { - registerCommonExtensions(project) + val hideFromObjC = configuration.get( + ComposeConfiguration.HIDE_DECLARATION_FROM_OBJC_ENABLED_KEY, + true + ) + val hideFromObjCDeclarationsSet = if (hideFromObjC) { + HideFromObjCDeclarationsSet.create() + } else { + null + } + val classStabilityInferredCollection = ClassStabilityInferredCollection() + registerCommonExtensions(project, hideFromObjCDeclarationsSet, classStabilityInferredCollection) IrGenerationExtension.registerExtension( project, - createComposeIrExtension(configuration) + createComposeIrExtension( + configuration, + hideFromObjCDeclarationsSet = hideFromObjCDeclarationsSet, + classStabilityInferredCollection = classStabilityInferredCollection + ) ) } } @@ -341,7 +372,11 @@ class ComposePluginRegistrar : org.jetbrains.kotlin.compiler.plugin.ComponentReg } } - fun registerCommonExtensions(project: Project) { + fun registerCommonExtensions( + project: Project, + hideFromObjCDeclarationsSet: HideFromObjCDeclarationsSet?, + classStabilityInferredCollection: ClassStabilityInferredCollection? + ) { StorageComponentContainerContributor.registerExtension( project, ComposableCallChecker() @@ -363,14 +398,22 @@ class ComposePluginRegistrar : org.jetbrains.kotlin.compiler.plugin.ComponentReg ) DescriptorSerializerPlugin.registerExtension( project, - ClassStabilityFieldSerializationPlugin() + ClassStabilityFieldSerializationPlugin(classStabilityInferredCollection) ) FirExtensionRegistrarAdapter.registerExtension(project, ComposeFirExtensionRegistrar()) + if (hideFromObjCDeclarationsSet != null) { + DescriptorSerializerPlugin.registerExtension( + project, + AddHiddenFromObjCSerializationPlugin(hideFromObjCDeclarationsSet) + ) + } } fun createComposeIrExtension( configuration: CompilerConfiguration, - moduleMetricsFactory: ((StabilityInferencer) -> ModuleMetrics)? = null + moduleMetricsFactory: ((StabilityInferencer) -> ModuleMetrics)? = null, + hideFromObjCDeclarationsSet: HideFromObjCDeclarationsSet?, + classStabilityInferredCollection: ClassStabilityInferredCollection? ): ComposeIrGenerationExtension { val liveLiteralsEnabled = configuration.getBoolean( ComposeConfiguration.LIVE_LITERALS_ENABLED_KEY, @@ -443,7 +486,9 @@ class ComposePluginRegistrar : org.jetbrains.kotlin.compiler.plugin.ComponentReg useK2 = useK2, strongSkippingEnabled = strongSkippingEnabled, stableTypeMatchers = stableTypeMatchers, - moduleMetricsFactory = moduleMetricsFactory + moduleMetricsFactory = moduleMetricsFactory, + hideFromObjCDeclarationsSet = hideFromObjCDeclarationsSet, + classStabilityInferredCollection = classStabilityInferredCollection, ) } } diff --git a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/analysis/Stability.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/analysis/Stability.kt index eee5edccc1f54..82e874a02572b 100644 --- a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/analysis/Stability.kt +++ b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/analysis/Stability.kt @@ -17,6 +17,7 @@ package androidx.compose.compiler.plugins.kotlin.analysis import androidx.compose.compiler.plugins.kotlin.ComposeFqNames +import androidx.compose.compiler.plugins.kotlin.lower.AbstractComposeLowering import androidx.compose.compiler.plugins.kotlin.lower.annotationClass import androidx.compose.compiler.plugins.kotlin.lower.isSyntheticComposableFunction import org.jetbrains.kotlin.backend.jvm.ir.isInlineClassType diff --git a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/AbstractComposeLowering.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/AbstractComposeLowering.kt index 906c58c4267b7..3aef7edf15209 100644 --- a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/AbstractComposeLowering.kt +++ b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/AbstractComposeLowering.kt @@ -32,6 +32,7 @@ import androidx.compose.compiler.plugins.kotlin.analysis.knownUnstable import androidx.compose.compiler.plugins.kotlin.irTrace import com.intellij.openapi.progress.ProcessCanceledException import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext +import org.jetbrains.kotlin.backend.common.lower.DeclarationIrBuilder import org.jetbrains.kotlin.backend.jvm.ir.isInlineClassType import org.jetbrains.kotlin.builtins.PrimitiveType import org.jetbrains.kotlin.descriptors.DescriptorVisibilities @@ -43,6 +44,7 @@ import org.jetbrains.kotlin.ir.builders.declarations.addValueParameter import org.jetbrains.kotlin.ir.builders.declarations.buildField import org.jetbrains.kotlin.ir.builders.declarations.buildFun import org.jetbrains.kotlin.ir.builders.declarations.buildProperty +import org.jetbrains.kotlin.ir.builders.irBlockBody import org.jetbrains.kotlin.ir.declarations.IrAnnotationContainer import org.jetbrains.kotlin.ir.declarations.IrAttributeContainer import org.jetbrains.kotlin.ir.declarations.IrClass @@ -50,6 +52,7 @@ import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin import org.jetbrains.kotlin.ir.declarations.IrField import org.jetbrains.kotlin.ir.declarations.IrFile import org.jetbrains.kotlin.ir.declarations.IrFunction +import org.jetbrains.kotlin.ir.declarations.IrPackageFragment import org.jetbrains.kotlin.ir.declarations.IrProperty import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction import org.jetbrains.kotlin.ir.declarations.IrTypeParameter @@ -123,10 +126,12 @@ import org.jetbrains.kotlin.ir.types.makeNullable import org.jetbrains.kotlin.ir.types.typeWith import org.jetbrains.kotlin.ir.util.DeepCopySymbolRemapper import org.jetbrains.kotlin.ir.util.SYNTHETIC_OFFSET +import org.jetbrains.kotlin.ir.util.addChild import org.jetbrains.kotlin.ir.util.defaultType import org.jetbrains.kotlin.ir.util.fqNameForIrSerialization import org.jetbrains.kotlin.ir.util.functions import org.jetbrains.kotlin.ir.util.getArgumentsWithIr +import org.jetbrains.kotlin.ir.util.getPackageFragment import org.jetbrains.kotlin.ir.util.getPropertyGetter import org.jetbrains.kotlin.ir.util.hasAnnotation import org.jetbrains.kotlin.ir.util.isFunction @@ -154,6 +159,15 @@ abstract class AbstractComposeLowering( val metrics: ModuleMetrics, val stabilityInferencer: StabilityInferencer ) : IrElementTransformerVoid(), ModuleLoweringPass { + + companion object { + var isJvmTarget: Boolean = false + } + + init { + isJvmTarget = context.platform?.isJvm() ?: false + } + protected val builtIns = context.irBuiltIns private val _composerIrClass = @@ -367,7 +381,18 @@ abstract class AbstractComposeLowering( is Stability.Parameter -> resolve(parameter) is Stability.Runtime -> { - val stableField = makeStabilityField().also { it.parent = declaration } + val customStabilityFieldName = when { + context.platform?.isJvm() == false -> declaration.uniqueStabilityFieldName() + else -> null + } + + val stableField = makeStabilityField(customStabilityFieldName).also { it.parent = declaration } + if (context.platform?.isJvm() == false) { + val root = declaration.getPackageFragment() + stableField.parent = root + val stabilityProp = makeStabilityProp(declaration.uniqueStabilityPropertyName(), stableField, root) + root.addChild(stabilityProp) + } IrGetFieldImpl( UNDEFINED_OFFSET, UNDEFINED_OFFSET, @@ -875,24 +900,41 @@ abstract class AbstractComposeLowering( ) } - fun makeStabilityField(): IrField { + fun IrClass.uniqueStabilityFieldName(): Name = Name.identifier( + kotlinFqName.asString().replace(".", "_") + KtxNameConventions.STABILITY_FLAG + ) + + fun IrClass.uniqueStabilityPropertyName(): Name = Name.identifier( + kotlinFqName.asString().replace(".", "_") + KtxNameConventions.STABILITY_PROP_FLAG + ) + + fun makeStabilityField(fieldName: Name? = null): IrField { return context.irFactory.buildField { startOffset = SYNTHETIC_OFFSET endOffset = SYNTHETIC_OFFSET - name = KtxNameConventions.STABILITY_FLAG - isStatic = context.platform.isJvm() + name = fieldName ?: KtxNameConventions.STABILITY_FLAG + isStatic = true isFinal = true type = context.irBuiltIns.intType visibility = DescriptorVisibilities.PUBLIC } } - protected fun makeStabilityProp(): IrProperty { + protected fun makeStabilityProp( + propertyName: Name? = null, + backingField: IrField, + parent: IrPackageFragment + ): IrProperty { return context.irFactory.buildProperty { startOffset = SYNTHETIC_OFFSET endOffset = SYNTHETIC_OFFSET - name = KtxNameConventions.STABILITY_PROP_FLAG - visibility = DescriptorVisibilities.PRIVATE + name = propertyName ?: KtxNameConventions.STABILITY_PROP_FLAG + visibility = DescriptorVisibilities.PUBLIC + isConst = true + }.also { property -> + backingField.correspondingPropertySymbol = property.symbol + property.backingField = backingField + property.parent = parent } } diff --git a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ClassStabilityFieldSerializationPlugin.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ClassStabilityFieldSerializationPlugin.kt index 66be1741e485c..b983ca5b24fb4 100644 --- a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ClassStabilityFieldSerializationPlugin.kt +++ b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ClassStabilityFieldSerializationPlugin.kt @@ -19,9 +19,11 @@ package androidx.compose.compiler.plugins.kotlin.lower import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.DescriptorVisibilities +import org.jetbrains.kotlin.library.metadata.KlibMetadataSerializerProtocol import org.jetbrains.kotlin.metadata.ProtoBuf import org.jetbrains.kotlin.metadata.deserialization.Flags.HAS_ANNOTATIONS import org.jetbrains.kotlin.metadata.serialization.MutableVersionRequirementTable +import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.serialization.DescriptorSerializer import org.jetbrains.kotlin.serialization.DescriptorSerializerPlugin import org.jetbrains.kotlin.serialization.SerializerExtension @@ -36,8 +38,29 @@ import org.jetbrains.kotlin.serialization.SerializerExtension * another module, so we have to use this plugin to flip the flag for all classes that we * synthesize the annotation on, even if the source of the class didn't have any annotations. */ -class ClassStabilityFieldSerializationPlugin : DescriptorSerializerPlugin { +class ClassStabilityFieldSerializationPlugin( + val classStabilityInferredCollection: ClassStabilityInferredCollection? +) : DescriptorSerializerPlugin { private val hasAnnotationFlag = HAS_ANNOTATIONS.toFlags(true) + + + private val annotationToAdd = ClassId.fromString("androidx/compose/runtime/internal/StabilityInferred") + + private fun createAnnotationProto(extension: SerializerExtension, value: Int): ProtoBuf.Annotation { + return ProtoBuf.Annotation.newBuilder().apply { + id = extension.stringTable.getQualifiedClassNameIndex(annotationToAdd) + val ix = extension.stringTable.getStringIndex("parameters") // Same as in StabilityInferred definition + addArgument(ProtoBuf.Annotation.Argument.newBuilder().apply { + setNameId(ix) + setValue( + ProtoBuf.Annotation.Argument.Value.newBuilder() + .setIntValue(value.toLong()) + .setType(ProtoBuf.Annotation.Argument.Value.Type.INT) + ) + }) + }.build() + } + override fun afterClass( descriptor: ClassDescriptor, proto: ProtoBuf.Class.Builder, @@ -60,5 +83,13 @@ class ClassStabilityFieldSerializationPlugin : DescriptorSerializerPlugin { if (proto.flags and hasAnnotationFlag == 0) { proto.flags = proto.flags or hasAnnotationFlag } + + val parametersValue = classStabilityInferredCollection?.getParametersValue(descriptor) + if (parametersValue != null) { + proto.addExtension( + KlibMetadataSerializerProtocol.classAnnotation, + createAnnotationProto(extension, parametersValue) + ) + } } } diff --git a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ClassStabilityInferredCollection.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ClassStabilityInferredCollection.kt new file mode 100644 index 0000000000000..0015b4e29fbb0 --- /dev/null +++ b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ClassStabilityInferredCollection.kt @@ -0,0 +1,38 @@ +/* + * Copyright 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package androidx.compose.compiler.plugins.kotlin.lower + +import org.jetbrains.kotlin.descriptors.ClassDescriptor +import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI +import org.jetbrains.kotlin.ir.declarations.IrClass + +/** + * Used with K1 only. + */ +class ClassStabilityInferredCollection { + + private val classesToValues = mutableMapOf() + + @OptIn(ObsoleteDescriptorBasedAPI::class) + fun addClass(c: IrClass, stabilityInferredParametersValue: Int) { + classesToValues[c.descriptor] = stabilityInferredParametersValue + } + + fun getParametersValue(descriptor: ClassDescriptor): Int? { + return classesToValues[descriptor] + } +} \ No newline at end of file diff --git a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ClassStabilityTransformer.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ClassStabilityTransformer.kt index 8d6397eaa6857..d1be6a7d86534 100644 --- a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ClassStabilityTransformer.kt +++ b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ClassStabilityTransformer.kt @@ -29,6 +29,7 @@ import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext import org.jetbrains.kotlin.backend.jvm.ir.isInlineClassType import org.jetbrains.kotlin.descriptors.DescriptorVisibilities import org.jetbrains.kotlin.ir.IrStatement +import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.IrFile @@ -38,8 +39,10 @@ import org.jetbrains.kotlin.ir.expressions.impl.IrConstructorCallImpl import org.jetbrains.kotlin.ir.expressions.impl.IrExpressionBodyImpl import org.jetbrains.kotlin.ir.types.defaultType import org.jetbrains.kotlin.ir.util.DeepCopySymbolRemapper +import org.jetbrains.kotlin.ir.util.addChild import org.jetbrains.kotlin.ir.util.constructors import org.jetbrains.kotlin.ir.util.defaultType +import org.jetbrains.kotlin.ir.util.getPackageFragment import org.jetbrains.kotlin.ir.util.isAnnotationClass import org.jetbrains.kotlin.ir.util.isAnonymousObject import org.jetbrains.kotlin.ir.util.isEnumClass @@ -64,7 +67,8 @@ class ClassStabilityTransformer( context: IrPluginContext, symbolRemapper: DeepCopySymbolRemapper, metrics: ModuleMetrics, - stabilityInferencer: StabilityInferencer + stabilityInferencer: StabilityInferencer, + private val classStabilityInferredCollection: ClassStabilityInferredCollection? ) : AbstractComposeLowering(context, symbolRemapper, metrics, stabilityInferencer), ClassLoweringPass, ModuleLoweringPass { @@ -84,6 +88,7 @@ class ClassStabilityTransformer( irFile.transformChildrenVoid(this) } + @OptIn(ObsoleteDescriptorBasedAPI::class) override fun visitClass(declaration: IrClass): IrStatement { val result = super.visitClass(declaration) val cls = result as? IrClass ?: return result @@ -181,6 +186,7 @@ class ClassStabilityTransformer( context.annotationsRegistrar.addMetadataVisibleAnnotationsToElement(cls, annotation) } else { cls.annotations += annotation + classStabilityInferredCollection?.addClass(cls, parameterMask) } cls.addStabilityMarkerField(stableExpr) @@ -188,7 +194,13 @@ class ClassStabilityTransformer( } private fun IrClass.addStabilityMarkerField(stabilityExpression: IrExpression) { - val stabilityField = makeStabilityField().apply { + val customStabilityFieldName = when { + context.platform?.isJvm() == false -> this.uniqueStabilityFieldName() + else -> null + } + val stabilityField = makeStabilityField( + fieldName = customStabilityFieldName + ).apply { parent = this@addStabilityMarkerField initializer = IrExpressionBodyImpl( UNDEFINED_OFFSET, @@ -200,13 +212,11 @@ class ClassStabilityTransformer( if (context.platform.isJvm()) { declarations += stabilityField } else { - // This ensures proper mangles in k/js and k/native (since kotlin 1.6.0-rc2) - val stabilityProp = makeStabilityProp().apply { - parent = this@addStabilityMarkerField - backingField = stabilityField - } - stabilityField.correspondingPropertySymbol = stabilityProp.symbol - declarations += stabilityProp + val root = this.getPackageFragment() + stabilityField.parent = root + + val stabilityProp = makeStabilityProp(this.uniqueStabilityPropertyName(), stabilityField, root) + root.addChild(stabilityProp) } } } diff --git a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposableFunctionBodyTransformer.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposableFunctionBodyTransformer.kt index afd9a53b2279a..8e1a022162b66 100644 --- a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposableFunctionBodyTransformer.kt +++ b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposableFunctionBodyTransformer.kt @@ -2865,7 +2865,8 @@ class ComposableFunctionBodyTransformer( private fun visitComposableCall(expression: IrCall): IrExpression { return when (expression.symbol.owner.kotlinFqName) { - ComposeFqNames.remember -> { + ComposeFqNames.remember, + DecoyFqNames.remember -> { if (intrinsicRememberEnabled) { visitRememberCall(expression) } else { diff --git a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposableTypeRemapper.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposableTypeRemapper.kt index 241fee54ec4f4..037fc7e5dc08c 100644 --- a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposableTypeRemapper.kt +++ b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposableTypeRemapper.kt @@ -210,6 +210,7 @@ internal class DeepCopyIrTreeWithRemappedComposableTypes( } private fun IrFunction.needsComposableRemapping(): Boolean { + if (this.isDecoy()) return false // to preserve the original signature for decoys if ( needsComposableRemapping(dispatchReceiverParameter?.type) || needsComposableRemapping(extensionReceiverParameter?.type) || diff --git a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposerLambdaMemoization.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposerLambdaMemoization.kt index 99cacc5c202c4..dfa99ab3f1ef2 100644 --- a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposerLambdaMemoization.kt +++ b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/ComposerLambdaMemoization.kt @@ -98,6 +98,7 @@ import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.load.kotlin.PackagePartClassUtils import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.platform.isJs +import org.jetbrains.kotlin.platform.isWasm import org.jetbrains.kotlin.platform.jvm.isJvm private class CaptureCollector { @@ -837,11 +838,11 @@ class ComposerLambdaMemoization( val function = expression.function val argumentCount = function.valueParameters.size - val isJs = context.platform.isJs() - if (argumentCount > MAX_RESTART_ARGUMENT_COUNT && isJs) { + val isJsOrWasm = context.platform.isJs() || context.platform.isWasm() + if (argumentCount > MAX_RESTART_ARGUMENT_COUNT && isJsOrWasm) { error( "only $MAX_RESTART_ARGUMENT_COUNT parameters " + - "in @Composable lambda are supported on JS" + "in @Composable lambda are supported on K/JS or K/Wasm" ) } @@ -918,7 +919,7 @@ class ComposerLambdaMemoization( ): IrExpression { // Kotlin/JS doesn't have an optimization for non-capturing lambdas // https://youtrack.jetbrains.com/issue/KT-49923 - val skipNonCapturingLambdas = !context.platform.isJs() + val skipNonCapturingLambdas = !context.platform.isJs() && ! context.platform.isWasm() // If the function doesn't capture, Kotlin's default optimization is sufficient if (captures.isEmpty() && skipNonCapturingLambdas) { diff --git a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/decoys/AbstractDecoysLowering.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/decoys/AbstractDecoysLowering.kt index f232b69ecc52c..8b523ea0362d0 100644 --- a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/decoys/AbstractDecoysLowering.kt +++ b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/decoys/AbstractDecoysLowering.kt @@ -21,8 +21,13 @@ import androidx.compose.compiler.plugins.kotlin.ModuleMetrics import androidx.compose.compiler.plugins.kotlin.analysis.StabilityInferencer import androidx.compose.compiler.plugins.kotlin.lower.AbstractComposeLowering import androidx.compose.compiler.plugins.kotlin.lower.includeFileNameInExceptionTrace +import androidx.compose.compiler.plugins.kotlin.lower.isSyntheticComposableFunction import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext +import org.jetbrains.kotlin.backend.common.ir.isExpect import org.jetbrains.kotlin.backend.common.serialization.signature.IdSignatureSerializer +import org.jetbrains.kotlin.backend.jvm.ir.propertyIfAccessor +import org.jetbrains.kotlin.descriptors.Modality +import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.IrConstructor import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin import org.jetbrains.kotlin.ir.declarations.IrFile @@ -33,8 +38,11 @@ import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.util.DeepCopySymbolRemapper import org.jetbrains.kotlin.ir.util.hasAnnotation import org.jetbrains.kotlin.ir.util.isEnumClass +import org.jetbrains.kotlin.ir.util.isInterface import org.jetbrains.kotlin.ir.util.isLocal import org.jetbrains.kotlin.ir.util.parentAsClass +import org.jetbrains.kotlin.ir.util.parentClassOrNull +import org.jetbrains.kotlin.ir.util.defaultType abstract class AbstractDecoysLowering( pluginContext: IrPluginContext, @@ -62,10 +70,25 @@ abstract class AbstractDecoysLowering( } } - protected fun IrFunction.shouldBeRemapped(): Boolean = - !isLocalFunction() && + private fun IrFunction.isSAM(): Boolean { + return (parent as? IrClass).let { + it?.isInterface == true && + it.isFun && + (this as? IrSimpleFunction)?.modality == Modality.ABSTRACT + } || (this as? IrSimpleFunction)?.overriddenSymbols?.any { + it.owner.isSAM() + } == true + } + + protected fun IrFunction.shouldBeRemapped(): Boolean { + return !isLocalFunction() && !isEnumConstructor() && - (hasComposableAnnotation() || hasComposableParameter()) + (hasComposableAnnotation() || hasComposableParameter()) && + !isSAM() && + !(parentClassOrNull?.defaultType?.isSyntheticComposableFunction() ?: false) && + !isExpect && !propertyIfAccessor.isExpect + + } private fun IrFunction.isLocalFunction(): Boolean = origin == IrDeclarationOrigin.LOCAL_FUNCTION_FOR_LAMBDA || diff --git a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/decoys/CreateDecoysTransformer.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/decoys/CreateDecoysTransformer.kt index df2db0c809200..6505e82880e34 100644 --- a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/decoys/CreateDecoysTransformer.kt +++ b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/decoys/CreateDecoysTransformer.kt @@ -19,6 +19,8 @@ package androidx.compose.compiler.plugins.kotlin.lower.decoys import androidx.compose.compiler.plugins.kotlin.ModuleMetrics import androidx.compose.compiler.plugins.kotlin.analysis.StabilityInferencer import androidx.compose.compiler.plugins.kotlin.lower.ModuleLoweringPass +import androidx.compose.compiler.plugins.kotlin.lower.function +import androidx.compose.compiler.plugins.kotlin.lower.isSyntheticComposableFunction import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext import org.jetbrains.kotlin.backend.common.ir.moveBodyTo import org.jetbrains.kotlin.backend.common.lower.DeclarationIrBuilder @@ -30,26 +32,19 @@ import org.jetbrains.kotlin.ir.builders.declarations.buildFun import org.jetbrains.kotlin.ir.builders.irBlockBody import org.jetbrains.kotlin.ir.builders.irCall import org.jetbrains.kotlin.ir.builders.irReturn -import org.jetbrains.kotlin.ir.declarations.IrConstructor -import org.jetbrains.kotlin.ir.declarations.IrDeclarationContainer -import org.jetbrains.kotlin.ir.declarations.IrDeclarationParent -import org.jetbrains.kotlin.ir.declarations.IrFunction -import org.jetbrains.kotlin.ir.declarations.IrModuleFragment -import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction -import org.jetbrains.kotlin.ir.declarations.IrValueParameter +import org.jetbrains.kotlin.ir.declarations.* +import org.jetbrains.kotlin.ir.expressions.IrDelegatingConstructorCall import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.IrExpressionBody import org.jetbrains.kotlin.ir.expressions.IrGetValue import org.jetbrains.kotlin.ir.expressions.impl.IrConstructorCallImpl -import org.jetbrains.kotlin.ir.util.DeepCopySymbolRemapper -import org.jetbrains.kotlin.ir.util.addChild -import org.jetbrains.kotlin.ir.util.constructors -import org.jetbrains.kotlin.ir.util.copyTo -import org.jetbrains.kotlin.ir.util.copyTypeParametersFrom -import org.jetbrains.kotlin.ir.util.defaultType -import org.jetbrains.kotlin.ir.util.hasDefaultValue -import org.jetbrains.kotlin.ir.util.patchDeclarationParents -import org.jetbrains.kotlin.ir.util.remapTypeParameters +import org.jetbrains.kotlin.ir.types.IrSimpleType +import org.jetbrains.kotlin.ir.types.IrType +import org.jetbrains.kotlin.ir.types.IrTypeArgument +import org.jetbrains.kotlin.ir.types.IrTypeProjection +import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl +import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection +import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.name.Name @@ -170,8 +165,12 @@ class CreateDecoysTransformer( super.visitConstructor(copied) as IrConstructor return declaration.apply { + // keep the original delegating constructor call to keep the IR valid (according to kotlin backend expectations) + val delegatingConstructorCall = this.body?.statements?.firstOrNull { + it is IrDelegatingConstructorCall + } setDecoyAnnotation(newName.asString()) - stubBody() + stubBody(delegatingConstructorCall) } } @@ -229,6 +228,15 @@ class CreateDecoysTransformer( newFunction.body = original.moveBodyTo(newFunction) ?.copyWithNewTypeParams(original, newFunction) + val oldBody = original.body + // we need to clean the original body before types remapping (to not remap body, it's moved to a new function). + // also see fun IrFunction.stubBody + original.body = null + + // we have to remap original types (in parameters) to get rid of ComposableFunctionX references. + // this way the `original` will produce a correct signature stored in DecoyImplementation annotation + original.remapComposableFunctionReferences() + newFunction.addDecoyImplementationAnnotation(newName.asString(), original.getSignatureId()) newFunction.valueParameters.forEach { @@ -238,9 +246,42 @@ class CreateDecoysTransformer( ) } + // restore the old body to make `stubBody` work correctly (only abstract functions can have empty body) + original.body = oldBody + return newFunction } + private fun IrFunction.remapComposableFunctionReferences() { + this.remapTypes(object : TypeRemapper { + override fun enterScope(irTypeParametersContainer: IrTypeParametersContainer) {} + override fun leaveScope() {} + + private fun remapTypeArgument(typeArgument: IrTypeArgument): IrTypeArgument = + if (typeArgument is IrTypeProjection) + makeTypeProjection(this.remapType(typeArgument.type), typeArgument.variance) + else + typeArgument + + override fun remapType(type: IrType): IrType { + if (type !is IrSimpleType) return type + if (type.isSyntheticComposableFunction()) { + val oldIrArguments = type.arguments + val functionCls = context.function(oldIrArguments.size - 1) + return IrSimpleTypeImpl( + null, + functionCls, + type.nullability, + oldIrArguments.map { remapTypeArgument(it) }, + type.annotations, + null + ) + } + return type + } + }) + } + /** * Expressions for default values can use other parameters. * In such cases we need to ensure that default values expressions use parameters of the new @@ -268,8 +309,9 @@ class CreateDecoysTransformer( }) } - private fun IrFunction.stubBody() { + private fun IrFunction.stubBody(vararg statements: IrStatement?) { body = DeclarationIrBuilder(context, symbol).irBlockBody { + statements.filterNotNull().forEach { + it } + irReturn( irCall(decoyStub).also { call -> call.putValueArgument(0, irConst(name.asString())) diff --git a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/decoys/DecoyFqNames.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/decoys/DecoyFqNames.kt index 37a409f43eeee..e48b92dfd833d 100644 --- a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/decoys/DecoyFqNames.kt +++ b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/decoys/DecoyFqNames.kt @@ -40,4 +40,5 @@ object DecoyFqNames { val CurrentComposerIntrinsic = ComposeFqNames.fqNameFor("\$get-currentComposer\$\$composable") val key = ComposeFqNames.fqNameFor("key\$composable") + val remember = ComposeFqNames.fqNameFor("remember\$composable") } diff --git a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/decoys/DecoyTransformBase.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/decoys/DecoyTransformBase.kt index c73f49b46b5aa..b196f32f462af 100644 --- a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/decoys/DecoyTransformBase.kt +++ b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/decoys/DecoyTransformBase.kt @@ -28,6 +28,7 @@ import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.declarations.IrDeclaration import org.jetbrains.kotlin.ir.declarations.IrDeclarationContainer import org.jetbrains.kotlin.ir.declarations.IrFunction +import org.jetbrains.kotlin.ir.declarations.lazy.IrLazyFunctionBase import org.jetbrains.kotlin.ir.expressions.IrConst import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.IrVararg @@ -57,10 +58,12 @@ internal interface DecoyTransformBase { val signatureBuilder: IdSignatureSerializer fun IrFunction.getSignatureId(): Long { - val signature = symbol.signature - ?: signatureBuilder.composeSignatureForDeclaration(this, false) - - return signature.getSignatureId() + return if (this is IrLazyFunctionBase) { + symbol.signature ?: signatureBuilder.composeSignatureForDeclaration(this, false) + } else { + // types may have been remapped, so `symbol.signature` is outdated. + signatureBuilder.composeSignatureForDeclaration(this, false) + }.getSignatureId() } private fun IdSignature.getSignatureId(): Long { diff --git a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/decoys/SubstituteDecoyCallsTransformer.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/decoys/SubstituteDecoyCallsTransformer.kt index 72a2809d2baff..7328d4c155bf1 100644 --- a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/decoys/SubstituteDecoyCallsTransformer.kt +++ b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/decoys/SubstituteDecoyCallsTransformer.kt @@ -16,18 +16,14 @@ package androidx.compose.compiler.plugins.kotlin.lower.decoys +import androidx.compose.compiler.plugins.kotlin.ComposeFqNames import androidx.compose.compiler.plugins.kotlin.ModuleMetrics import androidx.compose.compiler.plugins.kotlin.analysis.StabilityInferencer -import androidx.compose.compiler.plugins.kotlin.lower.ComposerParamTransformer -import androidx.compose.compiler.plugins.kotlin.lower.ModuleLoweringPass +import androidx.compose.compiler.plugins.kotlin.lower.* import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext import org.jetbrains.kotlin.backend.common.serialization.signature.IdSignatureSerializer import org.jetbrains.kotlin.ir.IrStatement -import org.jetbrains.kotlin.ir.declarations.IrConstructor -import org.jetbrains.kotlin.ir.declarations.IrFunction -import org.jetbrains.kotlin.ir.declarations.IrModuleFragment -import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction -import org.jetbrains.kotlin.ir.declarations.IrValueParameter +import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.lazy.IrLazyFunctionBase import org.jetbrains.kotlin.ir.expressions.IrCall import org.jetbrains.kotlin.ir.expressions.IrConstructorCall @@ -41,12 +37,16 @@ import org.jetbrains.kotlin.ir.expressions.impl.IrDelegatingConstructorCallImpl import org.jetbrains.kotlin.ir.expressions.impl.IrFunctionReferenceImpl import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol -import org.jetbrains.kotlin.ir.util.DeepCopySymbolRemapper -import org.jetbrains.kotlin.ir.util.copyTypeAndValueArgumentsFrom -import org.jetbrains.kotlin.ir.util.patchDeclarationParents -import org.jetbrains.kotlin.ir.util.remapTypeParameters +import org.jetbrains.kotlin.ir.types.IrSimpleType +import org.jetbrains.kotlin.ir.types.IrType +import org.jetbrains.kotlin.ir.types.IrTypeArgument +import org.jetbrains.kotlin.ir.types.IrTypeProjection +import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl +import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection +import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid +import org.jetbrains.kotlin.types.Variance /** * Replaces all decoys references to their implementations created in [CreateDecoysTransformer]. @@ -116,7 +116,6 @@ class SubstituteDecoyCallsTransformer( if (declaration.isDecoy()) { return super.visitSimpleFunction(declaration) } - remapOverriddenSymbols(declaration) return super.visitSimpleFunction(declaration) } @@ -157,7 +156,7 @@ class SubstituteDecoyCallsTransformer( constructorTypeArgumentsCount = expression.constructorTypeArgumentsCount ).let { it.copyTypeAndValueArgumentsFrom(expression) - return@let it.copyWithNewTypeParams(callee, actualConstructor) + it } return super.visitConstructorCall(updatedCall) @@ -182,7 +181,7 @@ class SubstituteDecoyCallsTransformer( valueArgumentsCount = expression.valueArgumentsCount, ).let { it.copyTypeAndValueArgumentsFrom(expression) - return@let it.copyWithNewTypeParams(callee, actualConstructor) + it } return super.visitDelegatingConstructorCall(updatedCall) @@ -207,7 +206,7 @@ class SubstituteDecoyCallsTransformer( superQualifierSymbol = expression.superQualifierSymbol ).let { it.copyTypeAndValueArgumentsFrom(expression) - return@let it.copyWithNewTypeParams(callee, actualFunction) + it } return super.visitCall(updatedCall) } @@ -231,17 +230,77 @@ class SubstituteDecoyCallsTransformer( reflectionTarget = expression.reflectionTarget ).let { it.copyTypeAndValueArgumentsFrom(expression) - return@let it.copyWithNewTypeParams(callee, actualFunction) + it } return super.visitFunctionReference(updatedReference) } private val addComposerParameterInplace = object : IrElementTransformerVoid() { - private val сomposerParamTransformer = ComposerParamTransformer( + private val composerParamTransformer = ComposerParamTransformer( context, symbolRemapper, stabilityInferencer, true, metrics ) + + private fun IrType.isComposable(): Boolean { + return annotations.hasAnnotation(ComposeFqNames.Composable) + } + + private val composerType = composerIrClass.defaultType.replaceArgumentsWithStarProjections() + + private fun IrConstructorCall.isComposableAnnotation() = + this.symbol.owner.parent.fqNameForIrSerialization == ComposeFqNames.Composable + + val typeRemapper = object : TypeRemapper { + override fun enterScope(irTypeParametersContainer: IrTypeParametersContainer) {} + override fun leaveScope() {} + + private fun remapTypeArgument(typeArgument: IrTypeArgument): IrTypeArgument = + if (typeArgument is IrTypeProjection) + makeTypeProjection(this.remapType(typeArgument.type), typeArgument.variance) + else + typeArgument + + private fun IrType.isComposableFunction(): Boolean { + return isSyntheticComposableFunction() || (isFunction() && hasComposableAnnotation()) + } + + override fun remapType(type: IrType): IrType { + if (type !is IrSimpleType) return type + if (!type.isComposableFunction()) return type + + val oldIrArguments = type.arguments + val realParams = oldIrArguments.size - 1 + var extraArgs = listOf( + // composer param + makeTypeProjection( + composerType, + Variance.INVARIANT + ) + ) + val changedParams = changedParamCount(realParams, 1) + extraArgs = extraArgs + (0 until changedParams).map { + makeTypeProjection(context.irBuiltIns.intType, Variance.INVARIANT) + } + val newIrArguments = + oldIrArguments.subList(0, oldIrArguments.size - 1) + + extraArgs + + oldIrArguments.last() + + val newArgSize = oldIrArguments.size - 1 + extraArgs.size + val functionCls = context.function(newArgSize) + + return IrSimpleTypeImpl( + null, + functionCls, + type.nullability, + newIrArguments.map { remapTypeArgument(it) }, + type.annotations.filter { !it.isComposableAnnotation() }, + null + ) + } + } + override fun visitSimpleFunction(declaration: IrSimpleFunction): IrStatement { - return сomposerParamTransformer.visitSimpleFunction(declaration) + return composerParamTransformer.visitSimpleFunction(declaration) } } @@ -269,6 +328,9 @@ class SubstituteDecoyCallsTransformer( else -> decoysTransformer.visitFunction(declaration) }.also { decoysTransformer.updateParents() + (it as IrFunction).getComposableForDecoy().also { + it.owner.remapTypes(addComposerParameterInplace.typeRemapper) + } owner.parent.transformChildrenVoid(addComposerParameterInplace) } as IrFunction } else owner diff --git a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/hiddenfromobjc/AddHiddenFromObjCLowering.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/hiddenfromobjc/AddHiddenFromObjCLowering.kt new file mode 100644 index 0000000000000..6a6cca98a3cd0 --- /dev/null +++ b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/hiddenfromobjc/AddHiddenFromObjCLowering.kt @@ -0,0 +1,128 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package androidx.compose.compiler.plugins.kotlin.lower.hiddenfromobjc + +import androidx.compose.compiler.plugins.kotlin.ModuleMetrics +import androidx.compose.compiler.plugins.kotlin.analysis.StabilityInferencer +import androidx.compose.compiler.plugins.kotlin.lower.AbstractComposeLowering +import androidx.compose.compiler.plugins.kotlin.lower.ComposableSymbolRemapper +import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext +import org.jetbrains.kotlin.descriptors.DescriptorVisibilities +import org.jetbrains.kotlin.ir.IrStatement +import org.jetbrains.kotlin.ir.declarations.* +import org.jetbrains.kotlin.ir.expressions.impl.IrConstructorCallImpl +import org.jetbrains.kotlin.ir.symbols.IrClassSymbol +import org.jetbrains.kotlin.ir.types.IrSimpleType +import org.jetbrains.kotlin.ir.types.IrType +import org.jetbrains.kotlin.ir.types.classOrNull +import org.jetbrains.kotlin.ir.types.defaultType +import org.jetbrains.kotlin.ir.util.* +import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid +import org.jetbrains.kotlin.name.ClassId +import org.jetbrains.kotlin.platform.konan.isNative + +/** + * AddHiddenFromObjCLowering looks for functions and properties with @Composable types and + * adds the `kotlin.native.HiddenFromObjC` annotation to them. + * @see https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.native/-hidden-from-obj-c/ + */ +class AddHiddenFromObjCLowering( + private val pluginContext: IrPluginContext, + symbolRemapper: ComposableSymbolRemapper, + metrics: ModuleMetrics, + private val hideFromObjCDeclarationsSet: HideFromObjCDeclarationsSet, + stabilityInferencer: StabilityInferencer, +) : AbstractComposeLowering(pluginContext, symbolRemapper, metrics, stabilityInferencer) { + + private val hiddenFromObjCAnnotation: IrClassSymbol by lazy { + getTopLevelClass(ClassId.fromString("kotlin/native/HiddenFromObjC")) + } + + private val compositionLocalClassSymbol: IrClassSymbol by lazy { + getTopLevelClass(ClassId.fromString("androidx/compose/runtime/CompositionLocal")) + } + + override fun lower(module: IrModuleFragment) { + require(context.platform.isNative()) { + "AddHiddenFromObjCLowering is expected to run only for k/native. " + + "The platform - ${context.platform}" + } + module.transformChildrenVoid(this) + } + + override fun visitFunction(declaration: IrFunction): IrStatement { + val f = super.visitFunction(declaration) as IrFunction + if (f.isLocal || f.visibility != DescriptorVisibilities.PUBLIC) return f + + val shouldAdd = f.hasComposableAnnotation() || + f.typeParameters.any { it.defaultType.hasComposable() } || + f.valueParameters.any { it.type.hasComposable() } || + f.returnType.hasComposable() + + if (shouldAdd) { + f.addHiddenFromObjCAnnotation() + hideFromObjCDeclarationsSet.addToHide(f) + } + + return f + } + + override fun visitProperty(declaration: IrProperty): IrStatement { + val p = super.visitProperty(declaration) as IrProperty + if (p.isLocal || p.visibility != DescriptorVisibilities.PUBLIC) return p + + val shouldAdd = p.getter?.hasComposableAnnotation() == true || + p.getter?.returnType?.hasComposable() == true || + p.backingField?.type?.hasComposable() == true || + p.getter?.returnType?.isCompositionLocal() == true || + p.backingField?.type?.isCompositionLocal() == true + + if (shouldAdd) { + p.addHiddenFromObjCAnnotation() + hideFromObjCDeclarationsSet.addToHide(p) + } + + return p + } + + private fun IrType?.isCompositionLocal(): Boolean { + if (this == null) return false + if (this.classOrNull == compositionLocalClassSymbol) return true + return this.superTypes().any { + it.isCompositionLocal() + } + } + + private fun IrDeclaration.addHiddenFromObjCAnnotation() { + val annotation = IrConstructorCallImpl.fromSymbolOwner( + type = hiddenFromObjCAnnotation.defaultType, + constructorSymbol = hiddenFromObjCAnnotation.constructors.first() + ) + pluginContext.annotationsRegistrar.addMetadataVisibleAnnotationsToElement(this, annotation) + } + + private fun IrType.hasComposable(): Boolean { + if (hasComposableAnnotation()) { + return true + } + + return when (this) { + is IrSimpleType -> arguments.any { (it as? IrType)?.hasComposable() == true } + else -> false + } + } +} diff --git a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/hiddenfromobjc/AddHiddenFromObjCSerializationPlugin.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/hiddenfromobjc/AddHiddenFromObjCSerializationPlugin.kt new file mode 100644 index 0000000000000..23422b72865e4 --- /dev/null +++ b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/hiddenfromobjc/AddHiddenFromObjCSerializationPlugin.kt @@ -0,0 +1,113 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package androidx.compose.compiler.plugins.kotlin.lower.hiddenfromobjc + +import org.jetbrains.kotlin.descriptors.ConstructorDescriptor +import org.jetbrains.kotlin.descriptors.FunctionDescriptor +import org.jetbrains.kotlin.descriptors.PropertyDescriptor +import org.jetbrains.kotlin.library.metadata.KlibMetadataSerializerProtocol +import org.jetbrains.kotlin.metadata.ProtoBuf +import org.jetbrains.kotlin.metadata.deserialization.Flags +import org.jetbrains.kotlin.metadata.serialization.MutableVersionRequirementTable +import org.jetbrains.kotlin.name.ClassId +import org.jetbrains.kotlin.serialization.DescriptorSerializer +import org.jetbrains.kotlin.serialization.DescriptorSerializerPlugin +import org.jetbrains.kotlin.serialization.SerializerExtension + +/** + * Adds the kotlin.native.HiddenFromObjC annotation to the descriptors of declarations + * in [hideFromObjCDeclarationsSet]. + * + * @see [HideFromObjCDeclarationsSet] + */ +class AddHiddenFromObjCSerializationPlugin( + private val hideFromObjCDeclarationsSet: HideFromObjCDeclarationsSet +) : DescriptorSerializerPlugin { + + private val hasAnnotationFlag = Flags.HAS_ANNOTATIONS.toFlags(true) + + private val annotationToAdd = ClassId.fromString("kotlin/native/HiddenFromObjC") + + private fun createAnnotationProto(extension: SerializerExtension) = + ProtoBuf.Annotation.newBuilder().apply { + id = extension.stringTable.getQualifiedClassNameIndex(annotationToAdd) + }.build() + + override fun afterConstructor( + descriptor: ConstructorDescriptor, + proto: ProtoBuf.Constructor.Builder, + versionRequirementTable: MutableVersionRequirementTable?, + childSerializer: DescriptorSerializer, + extension: SerializerExtension + ) { + if (descriptor in hideFromObjCDeclarationsSet) { + val annotationProto = createAnnotationProto(extension) + proto.addExtension(KlibMetadataSerializerProtocol.constructorAnnotation, annotationProto) + proto.flags = proto.flags or hasAnnotationFlag + } + } + + override fun afterFunction( + descriptor: FunctionDescriptor, + proto: ProtoBuf.Function.Builder, + versionRequirementTable: MutableVersionRequirementTable?, + childSerializer: DescriptorSerializer, + extension: SerializerExtension + ) { + if (descriptor in hideFromObjCDeclarationsSet) { + val annotationProto = createAnnotationProto(extension) + proto.addExtension(KlibMetadataSerializerProtocol.functionAnnotation, annotationProto) + proto.flags = proto.flags or hasAnnotationFlag + } + } + + override fun afterProperty( + descriptor: PropertyDescriptor, + proto: ProtoBuf.Property.Builder, + versionRequirementTable: MutableVersionRequirementTable?, + childSerializer: DescriptorSerializer, + extension: SerializerExtension + ) { + if (descriptor in hideFromObjCDeclarationsSet) { + val annotationProto = createAnnotationProto(extension) + proto.addExtension(KlibMetadataSerializerProtocol.propertyAnnotation, annotationProto) + proto.flags = proto.flags or hasAnnotationFlag + + // Add the annotation for the getter too if it's Composable + val getterDescriptor = descriptor.getter + if (getterDescriptor != null && getterDescriptor in hideFromObjCDeclarationsSet) { + val annotationForGetter = createAnnotationProto(extension) + proto.addExtension( + KlibMetadataSerializerProtocol.propertyGetterAnnotation, + annotationForGetter + ) + proto.getterFlags = proto.getterFlags or hasAnnotationFlag + } + + // Add the annotation for the setter too if it's Composable + val setterDescriptor = descriptor.getter + if (setterDescriptor != null && setterDescriptor in hideFromObjCDeclarationsSet) { + val annotationForSetter = createAnnotationProto(extension) + proto.addExtension( + KlibMetadataSerializerProtocol.propertySetterAnnotation, + annotationForSetter + ) + proto.setterFlags = proto.setterFlags or hasAnnotationFlag + } + } + } +} diff --git a/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/hiddenfromobjc/HideFromObjCDeclarationsSet.kt b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/hiddenfromobjc/HideFromObjCDeclarationsSet.kt new file mode 100644 index 0000000000000..1d7447c4f9160 --- /dev/null +++ b/compose/compiler/compiler-hosted/src/main/java/androidx/compose/compiler/plugins/kotlin/lower/hiddenfromobjc/HideFromObjCDeclarationsSet.kt @@ -0,0 +1,73 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package androidx.compose.compiler.plugins.kotlin.lower.hiddenfromobjc + +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI +import org.jetbrains.kotlin.ir.declarations.IrFunction +import org.jetbrains.kotlin.ir.declarations.IrProperty +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe + +/** + * Represents a set of declarations that should have + * kotlin.native.HiddenFromObjC annotation added in their IR and descriptors. + * + * It's used by [AddHiddenFromObjCSerializationPlugin] to determine + * if there's a need to modify the declaration descriptor before it's serialized. + * This set is populated by [AddHiddenFromObjCLowering]. + * + * More context: + * The reason why we need this set is due to k/native ObjCExportMapper.kt is + * using descriptors to look at the declaration annotations. + * When ObjCExportMapper.kt migrates to FIR, we will need to simply remove this interface + * and [AddHiddenFromObjCSerializationPlugin]. + * Adding the annotation in IR - [AddHiddenFromObjCLowering] will likely be enough. + */ +interface HideFromObjCDeclarationsSet { + + fun shouldHide(descriptor: DeclarationDescriptor): Boolean = contains(descriptor) + fun addToHide(function: IrFunction) + fun addToHide(property: IrProperty) + + operator fun contains(item: DeclarationDescriptor): Boolean + + companion object { + fun create(): HideFromObjCDeclarationsSet = HideFromObjCDeclarationsSetImpl() + } +} + +@OptIn(ObsoleteDescriptorBasedAPI::class) +private class HideFromObjCDeclarationsSetImpl : HideFromObjCDeclarationsSet { + + private val set = mutableSetOf() + + override fun shouldHide(descriptor: DeclarationDescriptor): Boolean = + set.contains(descriptor.fqNameSafe) + + override fun addToHide(function: IrFunction) { + set.add(function.descriptor.fqNameSafe) + } + + override fun addToHide(property: IrProperty) { + set.add(property.descriptor.fqNameSafe) + } + + override fun contains(item: DeclarationDescriptor): Boolean { + return set.contains(item.fqNameSafe) + } +} diff --git a/compose/foundation/foundation/build.gradle b/compose/foundation/foundation/build.gradle index 58190c2a372ee..3306be0e7d5dc 100644 --- a/compose/foundation/foundation/build.gradle +++ b/compose/foundation/foundation/build.gradle @@ -28,7 +28,7 @@ plugins { id("AndroidXPlugin") id("com.android.library") id("AndroidXComposePlugin") - id("AndroidXPaparazziPlugin") + //id("AndroidXPaparazziPlugin") } diff --git a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text/StringHelpers.android.kt b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text/StringHelpers.android.kt index d13a05b5fc346..adcc021f35fa6 100644 --- a/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text/StringHelpers.android.kt +++ b/compose/foundation/foundation/src/androidMain/kotlin/androidx/compose/foundation/text/StringHelpers.android.kt @@ -16,29 +16,25 @@ package androidx.compose.foundation.text -import androidx.emoji2.text.EmojiCompat +//import androidx.emoji2.text.EmojiCompat import java.text.BreakIterator internal actual fun String.findPrecedingBreak(index: Int): Int { - val emojiBreak = - getEmojiCompatIfLoaded()?.getEmojiStart(this, maxOf(0, index - 1))?.takeUnless { it == -1 } - if (emojiBreak != null) return emojiBreak - val it = BreakIterator.getCharacterInstance() it.setText(this) return it.preceding(index) } internal actual fun String.findFollowingBreak(index: Int): Int { - val emojiBreak = getEmojiCompatIfLoaded()?.getEmojiEnd(this, index)?.takeUnless { it == -1 } - if (emojiBreak != null) return emojiBreak +// val emojiBreak = getEmojiCompatIfLoaded()?.getEmojiEnd(this, index)?.takeUnless { it == -1 } +// if (emojiBreak != null) return emojiBreak val it = BreakIterator.getCharacterInstance() it.setText(this) return it.following(index) } -private fun getEmojiCompatIfLoaded(): EmojiCompat? = - if (EmojiCompat.isConfigured()) - EmojiCompat.get().takeIf { it.loadState == EmojiCompat.LOAD_STATE_SUCCEEDED } - else null +//private fun getEmojiCompatIfLoaded(): EmojiCompat? = +// if (EmojiCompat.isConfigured()) +// EmojiCompat.get().takeIf { it.loadState == EmojiCompat.LOAD_STATE_SUCCEEDED } +// else null \ No newline at end of file diff --git a/compose/material/material/build.gradle b/compose/material/material/build.gradle index 3ea901210ce1d..5341f785e0174 100644 --- a/compose/material/material/build.gradle +++ b/compose/material/material/build.gradle @@ -28,7 +28,7 @@ plugins { id("AndroidXPlugin") id("com.android.library") id("AndroidXComposePlugin") - id("AndroidXPaparazziPlugin") + //id("AndroidXPaparazziPlugin") } androidXMultiplatform { diff --git a/compose/material/material/icons/generator/src/main/kotlin/androidx/compose/material/icons/generator/IconProcessor.kt b/compose/material/material/icons/generator/src/main/kotlin/androidx/compose/material/icons/generator/IconProcessor.kt index 732b652d5bb98..6f74363cb3f11 100644 --- a/compose/material/material/icons/generator/src/main/kotlin/androidx/compose/material/icons/generator/IconProcessor.kt +++ b/compose/material/material/icons/generator/src/main/kotlin/androidx/compose/material/icons/generator/IconProcessor.kt @@ -189,11 +189,13 @@ private fun writeApiFile(icons: List, file: File) { /** * Ensures that [generatedFile] matches the checked-in API surface in [expectedFile]. */ +@Suppress("UNUSED_PARAMETER") private fun checkApi(expectedFile: File, generatedFile: File) { check(expectedFile.exists()) { "API file at ${expectedFile.canonicalPath} does not exist!" } + /* check(expectedFile.readText() == generatedFile.readText()) { """Found differences when comparing API files! |Please check the difference and copy over the changes if intended. @@ -203,6 +205,7 @@ private fun checkApi(expectedFile: File, generatedFile: File) { |uploading. """.trimMargin() } + */ } /** diff --git a/compose/material3/material3/build.gradle b/compose/material3/material3/build.gradle index f59007cdfde9f..c7b4e3acc61af 100644 --- a/compose/material3/material3/build.gradle +++ b/compose/material3/material3/build.gradle @@ -28,7 +28,7 @@ plugins { id("AndroidXPlugin") id("com.android.library") id("AndroidXComposePlugin") - id("AndroidXPaparazziPlugin") + //id("AndroidXPaparazziPlugin") } androidXMultiplatform { diff --git a/compose/ui/ui-inspection/build.gradle b/compose/ui/ui-inspection/build.gradle index e409f2db3acf4..2b5359d69501d 100644 --- a/compose/ui/ui-inspection/build.gradle +++ b/compose/ui/ui-inspection/build.gradle @@ -87,11 +87,18 @@ android { main.resources.srcDirs += "src/main/proto" } - externalNativeBuild { - cmake { - path "src/main/cpp/CMakeLists.txt" - version libs.versions.cmake.get() - } +// We don't need NDK for developing Compose Multiplatform. +// It is only needed for Layout inspector for Android target. +// externalNativeBuild { +// cmake { +// path "src/main/cpp/CMakeLists.txt" +// version libs.versions.cmake.get() +// } +// } + + lintOptions { + // Restriction not important for inspectors, which only runs at dev-time + disable("SyntheticAccessor") } namespace "androidx.compose.ui.inspection" } diff --git a/datastore/datastore-compose-samples/build.gradle b/datastore/datastore-compose-samples/build.gradle index 698b179ccdb69..19c34df47c35b 100644 --- a/datastore/datastore-compose-samples/build.gradle +++ b/datastore/datastore-compose-samples/build.gradle @@ -29,7 +29,7 @@ plugins { id("AndroidXComposePlugin") id("org.jetbrains.kotlin.android") id("com.google.protobuf") - alias(libs.plugins.kotlinSerialization) + // alias(libs.plugins.kotlinSerialization) } dependencies { diff --git a/datastore/datastore-core/build.gradle b/datastore/datastore-core/build.gradle index 16e03195dde34..6c18154bc121a 100644 --- a/datastore/datastore-core/build.gradle +++ b/datastore/datastore-core/build.gradle @@ -72,9 +72,9 @@ androidXMultiplatform { mac() linux() ios() - android() +// android() - defaultPlatform(PlatformIdentifier.ANDROID) + defaultPlatform(PlatformIdentifier.JVM) sourceSets { all { diff --git a/datastore/datastore-preferences-core/build.gradle b/datastore/datastore-preferences-core/build.gradle index 712741f4f998c..299f667a55588 100644 --- a/datastore/datastore-preferences-core/build.gradle +++ b/datastore/datastore-preferences-core/build.gradle @@ -29,7 +29,7 @@ import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType plugins { id("AndroidXPlugin") - alias(libs.plugins.kotlinSerialization) + // alias(libs.plugins.kotlinSerialization) } def enableNative = KmpPlatformsKt.enableNative(project) diff --git a/datastore/datastore-sampleapp/build.gradle b/datastore/datastore-sampleapp/build.gradle index 9a94612e80a7a..4d114e1aa5505 100644 --- a/datastore/datastore-sampleapp/build.gradle +++ b/datastore/datastore-sampleapp/build.gradle @@ -28,7 +28,7 @@ plugins { id("com.android.application") id("org.jetbrains.kotlin.android") id("com.google.protobuf") - alias(libs.plugins.kotlinSerialization) + // alias(libs.plugins.kotlinSerialization) } dependencies { diff --git a/gradle.properties b/gradle.properties index 470ef1a352855..4fcb62099e96d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -5,14 +5,18 @@ org.gradle.configureondemand=true org.gradle.parallel=true org.gradle.caching=true org.gradle.welcome=never -org.gradle.projectcachedir=../../out/gradle-project-cache +org.gradle.projectcachedir=./out/gradle-project-cache # Disabled due to https://github.com/gradle/gradle/issues/18626 # org.gradle.vfs.watch=true # Reenabled in gradlew, but disabled in Studio until these errors become shown (b/268380971) or computed more quickly (https://github.com/gradle/gradle/issues/23272) org.gradle.dependency.verification=off org.gradle.dependency.verification.console=verbose -org.gradle.configuration-cache=true -org.gradle.configuration-cache.problems=fail +org.gradle.configuration-cache=false +org.gradle.configuration-cache.problems=warn +org.gradle.configuration-cache.max-problems=4000 +#org.gradle.unsafe.configuration-cache=false +#org.gradle.unsafe.configuration-cache-problems=warn +#org.gradle.unsafe.configuration-cache.max-problems=4000 # The following entries are workarounds # fullsdk-linux/**/package.xml -> b/291331139 @@ -22,7 +26,7 @@ org.gradle.configuration-cache.inputs.unsafe.ignore.file-system-checks=**/prebui android.lint.baselineOmitLineNumbers=true android.lint.printStackTrace=true -android.builder.sdkDownload=false +#android.builder.sdkDownload=false android.uniquePackageNames=true android.enableAdditionalTestOutput=true android.useAndroidX=true @@ -80,6 +84,12 @@ kotlin.options.suppressFreeCompilerArgsModificationWarning=true # Properties we often want to toggle ksp.version.check=false +# androidx.compose.multiplatformEnabled=true + +# properties for the fork +#androidx.compose.multiplatformEnabled=false +androidx.versionExtraCheckEnabled=false +#androidx.projects=COMPOSE # Annotation processors discovery from compile classpath is deprecated kapt.include.compile.classpath=false diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 570dfced6ae8a..9cac784e41a6f 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=../../../../tools/external/gradle/gradle-8.5-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip distributionSha256Sum=9d926787066a081739e8200858338b4a69e837c3a821a33aca9db09dd4a41026 zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 11901b7ebbc7f..2fe81a7d95e4f 100755 --- a/gradlew +++ b/gradlew @@ -1,6 +1,20 @@ -#!/usr/bin/env bash -set -o pipefail -set -e +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ############################################################################## ## @@ -8,52 +22,38 @@ set -e ## ############################################################################## -# --------- androidx specific code needed for build server. ------------------ - -SCRIPT_PATH="$(cd $(dirname $0) && pwd -P)" -if [ -n "$OUT_DIR" ] ; then - mkdir -p "$OUT_DIR" - OUT_DIR="$(cd $OUT_DIR && pwd -P)" - export GRADLE_USER_HOME="$OUT_DIR/.gradle" - export TMPDIR=$OUT_DIR -else - CHECKOUT_ROOT="$(cd $SCRIPT_PATH/../.. && pwd -P)" - export OUT_DIR="$CHECKOUT_ROOT/out" - export GRADLE_USER_HOME=~/.gradle -fi - -ORG_GRADLE_JVMARGS="$(cd $SCRIPT_PATH && grep org.gradle.jvmargs gradle.properties | sed 's/^/-D/')" -if [ -n "$DIST_DIR" ]; then - mkdir -p "$DIST_DIR" - DIST_DIR="$(cd $DIST_DIR && pwd -P)" - - # tell Gradle where to put a heap dump on failure - ORG_GRADLE_JVMARGS="$(echo $ORG_GRADLE_JVMARGS | sed "s|$| -XX:HeapDumpPath=$DIST_DIR|")" - - # We don't set a default DIST_DIR in an else clause here because Studio doesn't use gradlew - # and doesn't set DIST_DIR and we want gradlew and Studio to match -fi - -# Loading the AIDL lexer requires disabling Lint's bytecode verification -export ANDROID_LINT_SKIP_BYTECODE_VERIFIER=true - -# unset ANDROID_BUILD_TOP so that Lint doesn't think we're building the platform itself -unset ANDROID_BUILD_TOP -# ---------------------------------------------------------------------------- - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null APP_NAME="Gradle" APP_BASE_NAME=`basename "$0"` +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD="maximum" -warn ( ) { +warn () { echo "$*" } -die ( ) { +die () { echo echo "$*" echo @@ -64,6 +64,7 @@ die ( ) { cygwin=false msys=false darwin=false +nonstop=false case "`uname`" in CYGWIN* ) cygwin=true @@ -74,59 +75,13 @@ case "`uname`" in MINGW* ) msys=true ;; + NONSTOP* ) + nonstop=true + ;; esac -platform_suffix="x86" -case "$(arch)" in - arm64* ) - platform_suffix="arm64" -esac -# Attempt to set APP_HOME -# Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar -# --------- androidx specific code needed for lint and java. ------------------ - -# Pick the correct fullsdk for this OS. -if [ $darwin == "true" ]; then - plat="darwin" -else - plat="linux" -fi - -# Tests for lint checks default to using sdk defined by this variable. This removes a lot of -# setup from each lint module. -export ANDROID_HOME="$APP_HOME/../../prebuilts/fullsdk-$plat" -# override JAVA_HOME, because CI machines have it and it points to very old JDK -export JAVA_HOME="$APP_HOME/../../prebuilts/jdk/jdk17/$plat-$platform_suffix" -export STUDIO_GRADLE_JDK=$JAVA_HOME - -# Warn developers if they try to build top level project without the full checkout -[ ! -d "$JAVA_HOME" ] && echo "Failed to find: $JAVA_HOME - -Typically, this means either: -1. You are using the standalone AndroidX checkout, e.g. GitHub, which only supports - building a subset of projects. See CONTRIBUTING.md for details. -2. You are using the repo checkout, but the last repo sync failed. Use repo status - to check for projects which are partially-synced, e.g. showing ***NO BRANCH***." && exit -1 - -# ---------------------------------------------------------------------------- - # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then @@ -150,7 +105,7 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then MAX_FD_LIMIT=`ulimit -H -n` if [ $? -eq 0 ] ; then if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then @@ -170,8 +125,8 @@ if $darwin; then GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" fi -# For Cygwin, switch paths to Windows format before running java -if $cygwin ; then +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then APP_HOME=`cygpath --path --mixed "$APP_HOME"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` JAVACMD=`cygpath --unix "$JAVACMD"` @@ -199,292 +154,30 @@ if $cygwin ; then else eval `echo args$i`="\"$arg\"" fi - i=$((i+1)) + i=`expr $i + 1` done case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; esac fi -# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules -function splitJvmOpts() { - JVM_OPTS=("$@") -} -eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS -JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" - -#TODO: Remove HOME_SYSTEM_PROPERTY_ARGUMENT if https://github.com/gradle/gradle/issues/11433 gets fixed -HOME_SYSTEM_PROPERTY_ARGUMENT="" -if [ "$GRADLE_USER_HOME" != "" ]; then - HOME_SYSTEM_PROPERTY_ARGUMENT="-Duser.home=$GRADLE_USER_HOME" -fi -if [ "$TMPDIR" != "" ]; then - TMPDIR_ARG="-Djava.io.tmpdir=$TMPDIR" -fi - -if [[ " ${@} " =~ " --clean " ]]; then - cleanCaches=true -else - cleanCaches=false -fi - -if [[ " ${@} " =~ " --no-ci " ]]; then - disableCi=true -else - disableCi=false -fi - -# workaround for https://github.com/gradle/gradle/issues/18386 -if [[ " ${@} " =~ " --profile " ]]; then - mkdir -p reports -fi - -# Expand some arguments -for compact in "--ci" "--strict" "--clean" "--no-ci"; do - expanded="" - if [ "$compact" == "--ci" ]; then - if [ "$disableCi" == "false" ]; then - expanded="--strict\ - --stacktrace\ - -Pandroidx.summarizeStderr\ - -Pandroidx.enableAffectedModuleDetection\ - -Pandroidx.printTimestamps\ - --no-watch-fs\ - -Pandroidx.highMemory" - fi - fi - if [ "$compact" == "--strict" ]; then - expanded="-Pandroidx.validateNoUnrecognizedMessages\ - -Pandroidx.verifyUpToDate\ - --no-watch-fs" - if [ "$USE_ANDROIDX_REMOTE_BUILD_CACHE" == "" ]; then - expanded="$expanded --offline" - fi - fi - # if compact is something else then we parsed the argument above but - # still have to remove it (expanded == "") to avoid confusing Gradle - - # check whether this particular compat argument was passed (and therefore needs expansion) - if [[ " ${@} " =~ " $compact " ]]; then - # Expand an individual argument - # Start by making a copy of our list of arguments and iterating through the copy - for arg in "$@"; do - # Remove this argument from our list of arguments. - # By the time we've completed this loop, we will have removed the original copy of - # each argument, and potentially re-added a new copy or an expansion of each. - shift - # Determine whether to expand this argument - if [ "$arg" == "$compact" ]; then - # Add the expansion to our arguments - set -- "$@" $expanded - if [ "$expanded" != "" ]; then - echo "gradlew expanded '$compact' into '$expanded'" - echo - fi - # We avoid re-adding this argument itself back into the list for two reasons: - # 1. This argument might not be directly understood by Gradle - # 2. We want to enforce that all behaviors enabled by this flag can be toggled independently, - # so we don't want it to be easy to inadvertently check for the presence of this flag - # specifically - else - # Add this argument back into our arguments - set -- "$@" "$arg" - fi - done - fi -done - -if [[ " ${@} " =~ " -Pandroidx.highMemory " ]]; then - #Set the initial heap size to match the max heap size, - #by replacing a string like "-Xmx1g" with one like "-Xms1g -Xmx1g" - MAX_MEM=32g - ORG_GRADLE_JVMARGS="$(echo $ORG_GRADLE_JVMARGS | sed "s/-Xmx\([^ ]*\)/-Xms$MAX_MEM -Xmx$MAX_MEM/")" - - # Increase the compiler cache size: b/260643754 . Remove when updating to JDK 20 ( https://bugs.openjdk.org/browse/JDK-8295724 ) - ORG_GRADLE_JVMARGS="$(echo $ORG_GRADLE_JVMARGS | sed "s|$| -XX:ReservedCodeCacheSize=576M|")" -fi - -# check whether the user has requested profiling via yourkit -yourkitArgPrefix="androidx.profile.yourkitAgentPath" -yourkitAgentPath="" -if [[ " ${@}" =~ " -P$yourkitArgPrefix" ]]; then - for arg in "$@"; do - if echo "$arg" | grep "${yourkitArgPrefix}=" >/dev/null; then - yourkitAgentPath="$(echo "$arg" | sed "s/-P${yourkitArgPrefix}=//")" - fi - done - if [ "$yourkitAgentPath" == "" ]; then - echo "Error: $yourkitArgPrefix must be set to the path of the YourKit Java agent" >&2 - exit 1 - fi - if [ ! -e "$yourkitAgentPath" ]; then - echo "Error: $yourkitAgentPath does not exist" >&2 - exit 1 - fi - # add the agent to the path - export _JAVA_OPTIONS="$_JAVA_OPTIONS -agentpath:$yourkitAgentPath" - # add arguments - set -- "$@" --no-daemon --rerun-tasks - - # lots of blank lines because these messages are important - echo - echo - echo - echo - echo - # suggest --clean - if [ "$cleanCaches" == "false" ]; then - echo "When setting $yourkitArgPrefix you may also want to pass --clean" - fi - COLOR_YELLOW="\u001B[33m" - COLOR_CLEAR="\u001B[0m" - - echo -e "${COLOR_YELLOW}Also be sure to start the YourKit user interface and connect to the appropriate Java process (probably the Gradle Daemon)${COLOR_CLEAR}" - echo - echo - echo - echo - echo -fi - -if [[ " ${@} " =~ " --scan " ]]; then - if [[ " ${@} " =~ " --offline " ]]; then - echo "--scan incompatible with --offline" - echo "you could try --no-ci" - exit 1 - fi -fi - -function removeCaches() { - rm -rf $SCRIPT_PATH/.gradle - rm -rf $SCRIPT_PATH/buildSrc/.gradle - rm -f $SCRIPT_PATH/local.properties - if [ "$GRADLE_USER_HOME" != "" ]; then - rm -rf "$GRADLE_USER_HOME" - else - rm -rf ~/.gradle - fi - # https://github.com/gradle/gradle/issues/18386 - rm -rf $SCRIPT_PATH/reports - rm -rf $SCRIPT_PATH/build - rm -rf $OUT_DIR -} - -# Move any preexisting build scan to make room for a new one -# After moving a build scan several times it eventually gets deleted -function rotateBuildScans() { - filePrefix="$1" - iPlus1="10" - for i in $(seq 9 -1 1); do - mv "${filePrefix}.${i}.zip" "${filePrefix}.${iPlus1}.zip" 2>/dev/null || true - iPlus1=$i - done - mv ${filePrefix}.zip "${filePrefix}.1.zip" 2>/dev/null || true +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " } +APP_ARGS=`save "$@"` -function runGradle() { - processOutput=false - if [[ " ${@} " =~ " -Pandroidx.validateNoUnrecognizedMessages " ]]; then - processOutput=true - fi - if [[ " ${@} " =~ " -Pandroidx.summarizeStderr " ]]; then - processOutput=true - fi - if [[ "${@} " =~ " -Pandroidx.printTimestamps " ]]; then - processOutput=true - fi - if [ "$processOutput" == "true" ]; then - wrapper="$SCRIPT_PATH/development/build_log_processor.sh" - else - wrapper="" - fi +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" - RETURN_VALUE=0 - set -- "$@" -Dorg.gradle.projectcachedir="$OUT_DIR/gradle-project-cache" - # Disabled in Studio until these errors become shown (b/268380971) or computed more quickly (https://github.com/gradle/gradle/issues/23272) - if [[ " ${@} " =~ " --dependency-verification=" ]]; then - VERIFICATION_ARGUMENT="" # already specified by caller - else - VERIFICATION_ARGUMENT=--dependency-verification=strict - fi - if $wrapper "$JAVACMD" "${JVM_OPTS[@]}" $TMPDIR_ARG -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain $HOME_SYSTEM_PROPERTY_ARGUMENT $TMPDIR_ARG $VERIFICATION_ARGUMENT "$ORG_GRADLE_JVMARGS" "$@"; then - RETURN_VALUE=0 - else - # Print AndroidX-specific help message if build fails - # Have to do this build-failure detection in gradlew rather than in build.gradle - # so that this message still prints even if buildSrc itself fails - echo - echo For help with unexpected failures, see development/diagnose-build-failure/README.md - echo - RETURN_VALUE=1 - fi - - # If the caller specified where to save data, then also save the build scan data - if [ "$DIST_DIR" != "" ]; then - if [ "$GRADLE_USER_HOME" != "" ]; then - scanDir="$GRADLE_USER_HOME/build-scan-data" - if [ -e "$scanDir" ]; then - if [[ "$DISALLOW_TASK_EXECUTION" != "" ]]; then - zipPrefix="$DIST_DIR/scan-up-to-date" - else - zipPrefix="$DIST_DIR/scan" - fi - rotateBuildScans "$zipPrefix" - zipPath="${zipPrefix}.zip" - cd "$GRADLE_USER_HOME/build-scan-data" - zip -q -r "$zipPath" . - cd - - fi - fi - fi - return $RETURN_VALUE -} - -if [ "$cleanCaches" == true ]; then - echo "IF ./gradlew --clean FIXES YOUR BUILD; OPEN A BUG." - echo "In nearly all cases, it should not be necessary to run a clean build." - echo - # one case where it is convenient to have a clean build is for double-checking that a build failure isn't due to an incremental build failure - # another case where it is convenient to have a clean build is for performance testing - # another case where it is convenient to have a clean build is when you're modifying the build and may have introduced some errors but haven't shared your changes yet (at which point you should have fixed the errors) - - echo "Stopping Gradle daemons" - runGradle --stop || true - echo - - backupDir=~/androidx-build-state-backup - ./development/diagnose-build-failure/impl/backup-state.sh "$backupDir" --move # prints that it is saving state into this dir" - - echo "To restore this state later, run:" - echo - echo " ./development/diagnose-build-failure/impl/restore-state.sh $backupDir" - echo - echo "Running Gradle" - echo -fi - -if [[ "$DISALLOW_TASK_EXECUTION" != "" ]]; then - echo "Setting 'DISALLOW_TASK_EXECUTION' directly is forbidden. Did you mean -Pandroidx.verifyUpToDate ?" - echo "See TaskUpToDateValidator.java for more information" - exit 1 -fi - -runGradle "$@" -# Check whether we were given the "-Pandroidx.verifyUpToDate" argument -if [[ " ${@} " =~ " -Pandroidx.verifyUpToDate " ]]; then - # Re-run Gradle, and find all tasks that are unexpectly out of date - if ! DISALLOW_TASK_EXECUTION=true runGradle "$@" --continue; then - echo >&2 - echo "TaskUpToDateValidator's second build failed. To reproduce, try running './gradlew -Pandroidx.verifyUpToDate '" >&2 - exit 1 - fi -fi +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000000000..5093609d512a9 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,104 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/inspection/inspection/build.gradle b/inspection/inspection/build.gradle index 80270387742dc..d4030a1c4eae3 100644 --- a/inspection/inspection/build.gradle +++ b/inspection/inspection/build.gradle @@ -57,11 +57,13 @@ android { minSdkVersion 26 } - externalNativeBuild { - cmake { - path "src/main/native/CMakeLists.txt" - version "3.22.1" - } - } +// We don't need NDK for developing Compose Multiplatform. +// It is only needed for Layout inspector for Android target. +// externalNativeBuild { +// cmake { +// path "src/main/native/CMakeLists.txt" +// version "3.22.1" +// } +// } namespace "androidx.inspection" } diff --git a/jbdeps/android-sdk/downloadAndroidSdk b/jbdeps/android-sdk/downloadAndroidSdk new file mode 100755 index 0000000000000..23455c41e9545 --- /dev/null +++ b/jbdeps/android-sdk/downloadAndroidSdk @@ -0,0 +1,45 @@ +#!/bin/bash + +cd "$(dirname "$0")" + +clone() { + mkdir -p $1 + pushd $1 + git init + git config advice.detachedHead false + git fetch --depth=1 $2 $3 + git checkout FETCH_HEAD + popd +} + +# Commit hashes and sdk versions from https://android.googlesource.com/platform/manifest/+/refs/heads/androidx-main/default.xml + +downloadLinuxSDK() { + clone linux/platforms/android-32 https://android.googlesource.com/platform/prebuilts/fullsdk/platforms/android-32 master + clone linux/sources/android-32 https://android.googlesource.com/platform/prebuilts/fullsdk/sources/android-32 master + clone linux/build-tools/30.0.3 https://android.googlesource.com/platform/prebuilts/fullsdk-linux/build-tools/30.0.3 master + clone linux/platform-tools https://android.googlesource.com/platform/prebuilts/fullsdk-linux/platform-tools master + clone linux/tools https://android.googlesource.com/platform/prebuilts/fullsdk-linux/tools master +} + +downloadMacOsSDK() { + clone darwin/platforms/android-32 https://android.googlesource.com/platform/prebuilts/fullsdk/platforms/android-32 master + clone darwin/sources/android-32 https://android.googlesource.com/platform/prebuilts/fullsdk/sources/android-32 master + clone darwin/build-tools/30.0.3 https://android.googlesource.com/platform/prebuilts/fullsdk-darwin/build-tools/30.0.3 master + clone darwin/platform-tools https://android.googlesource.com/platform/prebuilts/fullsdk-darwin/platform-tools master + clone darwin/tools https://android.googlesource.com/platform/prebuilts/fullsdk-darwin/tools master +} + +if [[ "$OSTYPE" == "linux-gnu"* ]]; then + downloadLinuxSDK +elif [[ "$OSTYPE" == "darwin"* ]]; then + downloadMacOsSDK +elif [[ "$OSTYPE" == "cygwin" ]]; then + echo "Please download Android SDK manually (https://developer.android.com/studio)" +elif [[ "$OSTYPE" == "msys" ]]; then + echo "Please download Android SDK manually (https://developer.android.com/studio)" +elif [[ "$OSTYPE" == "win32" ]]; then + echo "Please download Android SDK manually (https://developer.android.com/studio)" +else + echo "Unknown OS" +fi diff --git a/jbdeps/jdk8/tools.jar b/jbdeps/jdk8/tools.jar new file mode 100644 index 0000000000000..3c66d15feea0a Binary files /dev/null and b/jbdeps/jdk8/tools.jar differ diff --git a/lifecycle/lifecycle-common/build.gradle b/lifecycle/lifecycle-common/build.gradle index bc25ff6d14ab3..20dc86090cccb 100644 --- a/lifecycle/lifecycle-common/build.gradle +++ b/lifecycle/lifecycle-common/build.gradle @@ -41,6 +41,13 @@ dependencies { testImplementation(libs.junit) testImplementation(libs.mockitoCore4) + + constraints { +// to fix Could not find lifecycle-runtime.aar (project :lifecycle:lifecycle-runtime) on a clean project +// implementation(project(":lifecycle:lifecycle-common-java8")) +// implementation(project(":lifecycle:lifecycle-runtime")) +// implementation(project(":lifecycle:lifecycle-livedata-core")) + } } androidx { diff --git a/navigation/navigation-compose/samples/build.gradle b/navigation/navigation-compose/samples/build.gradle index 8b287c06128d6..4fdde1571f694 100644 --- a/navigation/navigation-compose/samples/build.gradle +++ b/navigation/navigation-compose/samples/build.gradle @@ -29,7 +29,7 @@ plugins { id("AndroidXComposePlugin") id("org.jetbrains.kotlin.android") id ("kotlin-parcelize") - alias(libs.plugins.kotlinSerialization) + // alias(libs.plugins.kotlinSerialization) } dependencies { diff --git a/settings.gradle b/settings.gradle index 28789eb00b2cc..561355735a0b8 100644 --- a/settings.gradle +++ b/settings.gradle @@ -7,7 +7,9 @@ pluginManagement { maven { url = new File(buildscript.sourceFile.parent + "/../../prebuilts/androidx/external").getCanonicalFile() } - if (System.getenv("ALLOW_PUBLIC_REPOS") != null || System.getProperty("ALLOW_PUBLIC_REPOS") != null) { + def isJBFork = true + if (isJBFork) { + mavenLocal() mavenCentral() google() maven { @@ -37,8 +39,10 @@ buildscript { } skikoSetup.defineSkikoInVersionCatalog(settings) +def isJBFork = true + // Abort immediately if we're running in Studio, but not a managed instance of Studio. -if (startParameter.projectProperties.containsKey('android.injected.invoked.from.ide')) { +if (!isJBFork) { def expectedAgpVersion = System.getenv().get("EXPECTED_AGP_VERSION") if (expectedAgpVersion == null) { throw new Exception("Android Studio must be run from studiow or gradlew studio.") @@ -149,6 +153,33 @@ dependencyResolutionManagement { logger.warn("Using custom version ${metalavaOverride} of metalava due to METALAVA_VERSION being set.") version('metalava', metalavaOverride) } + def skikoOverride = System.getenv("SKIKO_VERSION") + if (skikoOverride != null) { + logger.warn("Using custom version ${skikoOverride} of SKIKO due to SKIKO_VERSION being set.") + version('skiko', skikoOverride) + } + String os = System.getProperty("os.name").toLowerCase(Locale.US) + String currentOsArtifact + if (os.contains("mac os x") || os.contains("darwin") || os.contains("osx")) { + def arch = System.getProperty("os.arch") + if (arch == "aarch64") { + currentOsArtifact = "skiko-awt-runtime-macos-arm64" + } else { + currentOsArtifact = "skiko-awt-runtime-macos-x64" + } + } else if (os.startsWith("win")) { + currentOsArtifact = "skiko-awt-runtime-windows-x64" + } else if (os.startsWith("linux") ) { + def arch = System.getProperty("os.arch") + if (arch == "aarch64") { + currentOsArtifact = "skiko-awt-runtime-linux-arm64" + } else { + currentOsArtifact = "skiko-awt-runtime-linux-x64" + } + } else { + throw GradleException("Unsupported operating system $os") + } + //library("skikoCurrentOs", "org.jetbrains.skiko", currentOsArtifact).versionRef("skiko") } } } @@ -181,7 +212,7 @@ private String getRequestedProjectSubsetName() { if (envProp.isPresent()) { return envProp.get().toUpperCase() } - return null + return "COMPOSE" } private String getRequestedProjectPrefix() { diff --git a/tracing/tracing-perfetto-binary/build.gradle b/tracing/tracing-perfetto-binary/build.gradle index 0a9ab3dff9347..52273cd091498 100644 --- a/tracing/tracing-perfetto-binary/build.gradle +++ b/tracing/tracing-perfetto-binary/build.gradle @@ -71,12 +71,14 @@ android { main.jniLibs.srcDirs += new File(unzippedPrebuiltsAarDir, "jni") } } else { // build .so files from scratch - externalNativeBuild { - cmake { - path "src/main/cpp/CMakeLists.txt" - version libs.versions.cmake.get() - } - } +// We don't need NDK for developing Compose Multiplatform. +// It is only needed for Benchmarking Android target. +// externalNativeBuild { +// cmake { +// path "src/main/cpp/CMakeLists.txt" +// version libs.versions.cmake.get() +// } +// } } namespace "androidx.tracing.perfetto.binary" }