Get Even More Visitors To Your Blog, Upgrade To A Business Listing >>

Optimizing Gradle Builds in Multi-module Projects

Posted on Oct 16 You're not alone if you've also struggled with sluggish Gradle builds in a multi-module project. Recently, we undertook the challenge of significantly reducing build times for a client with over 100 Kotlin Multiplatform modules, and achieved a more than 50% boost in speed across platforms. In this post, we'll walk you through the steps we took. We hope it proves valuable to fellow developers facing similar challenges.Before diving into optimizations, it's crucial to understand the baseline. Gather build times from all team members, ensuring the Gradle build cache is disabled. Use handy --no-build-cache option to any Gradle task command to run without build cache. Unsurprisingly, in our case, the Intel-based mac machines were really slow compared to Apple chip ones and we didn't have anyone with a Windows machine. This information is key for later comparison and improvement assessment.Note: One thing we realized that, some optimizations below might be more applicable to legacy or tech-debt-laden projects.Utilize the power of Gradle Build Scan to delve into the details of your builds. In my opinion, it's not just a diagnostic tool; it's a learning tool.In our case, we uncovered insights into the sluggishness of ios link tasks in the Kotlin Multiplatform setup. Comparing build scans on different CI machines helped identify the fastest configuration for a machine to use on our CI. Enabling parallel builds and analyzing the results through build scan reports further validated our improvements.Android Studio provides a built-in analyser tool. It inspects build performance and provides warning around potential issues.Disable JetifierUsing this, we noticed the lingering android.enableJetifier=true usage due to outdated Picasso library that didn't use AndroidX libraries. That might have hindered build speed too. Addressing this involved updating Picasso and removing the jetifier flag from gradle.properties.MultiDexThrough the Build Analyser, we also found unnecessary use of multiDexEnabled in few modules along with some old Gradle configurations. MultiDex was unnecessary with minSdkVersion as 21.We observed a significant number of modules relying on other modules via api dependency. The problem with having api dependencies is that Gradle would recompile them when implementation details change. It's because they appear on compile classpaths. This can have significant ripple of recompilations in a multi-module setup and affect the build times.To mitigate this, we shifted to using implementation for most dependencies, reserving api only for those exported as part of XCFramework.In a multi-subproject setup, Gradle may benefit greatly from parallel execution. With the shift from api to implementation, enabling parallel execution further slashed build times.Some Gradle plugins can be the culprits behind slower builds. Our project had a couple of Gradle plugins like that. They used to execute on every sync, every task and run through all the modules in the project.Scrutinize third-party plugins before integration, especially in a multi-module setup. Avoid unnecessary global application using subproject or allprojects blocks; apply plugins only where needed.When managing Kotlin Multiplatform (KMP) projects, it's crucial to evaluate the necessity of added KMP targets. In our experience, we found that inadvertently adding targets that aren't required for the project can introduce inefficiencies.For instance, we had inherited some modules with added JVM targets for certain KMP modules from older test modules. Over time, more modules were introduced, and the JVM target persisted without any actual use. This led to unnecessary JVM-related build and test tasks executing during the build phase.To address this, we recommend reviewing your KMP setup and removing any targets that don't contribute to the project's functionality. This not only streamlines the build process but also reduces unnecessary overhead, especially in a large multi-module project like ours.In Kotlin Multiplatform (KMP) projects with iOS components, the iOS build task can be a significant contributor to extended build times. Often, KMP project script files include configurations for multiple iOS architectures using iOSX64(), iosArm64(), and iosSimulatorArm64() targets, or the shorthand ios() that enables both iosArm64 and iOSX64.However, it's essential to optimize this setup, especially considering that building for unnecessary architectures can consume substantial time and resources. For example, even if your local development machine has an ARM architecture, building the X64 framework unnecessarily adds to build times, and vice versa for other architectures.Generally speaking, if things work on one architecture, then it's high likely that it would work on other architectures too. So it's fine if you at least keep building only one architecture locally. One approach is to introduce a boolean flag in your gradle.properties file, creating custom logic to enable a specific iOS target.Are you on a team where not everybody calling the Kotlin code wants or needs to build it locally? We've built KMMBridge, a tool to help streamline the iOS dev flow in KMP.While creating custom Gradle tasks might seem like a convenient way to handle common requirements, it's crucial to exercise caution, especially in a multi-module setup. In our experience, some custom tasks had unintended consequences on build times.For instance, we had custom tasks responsible for copying resources to another folder, but they ran across all modules, resulting in a noticeable slowdown during the build. To address this issue, we reconsidered our approach and opted for a different strategy to achieve the desired outcome without compromising build efficiency.The key takeaway is to ensure that custom tasks are appropriately configured to avoid unnecessary repetition across modules or tasksAlways stay current with Android Studio, Android Gradle Plugin, and Gradle itself. Each iteration brings improvements, potentially enhancing build speed.AGP 8.+Upgrade to Android Gradle Plugin 8.0.0 for default behaviors that optimize builds (i.e. non-transitive R classes), especially for apps with multiple modules.Configuration CacheNewer build tools have better support for configuration cache. It seems like a very promising feature that can drastically improve build speeds in certain cases.While configuration cache is a promising feature for faster builds, ensure compatibility with all your tools. As of Kotlin 1.9.10, the Kotlin Multiplatform plugin still lacks full support, limiting its effectiveness.Kotlin 1.9.20 is supposed to being full support for configuration cache. We're pretty pumped about it.By following these steps, you may turbocharge your Gradle builds, regardless of the project size or complexity. Happy coding! Let me know in the comments if you have questions. Also, you can reach out to me at @shaktiman_droid on Twitter, LinkedIn or Kotlin Slack. And if you find all this interesting, maybe you'd like to work with or work at Touchlab.Templates let you quickly answer FAQs or store snippets for re-use. Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment's permalink. Hide child comments as well Confirm For further actions, you may consider blocking this person and/or reporting abuse Cherif BOUCHELAGHEM - Jul 8 Tristan Elliott - Jul 27 Treep - Jul 27 David Rodriguez - Jul 26 We build solutions that get teams started smoothly with Kotlin Multiplatform and ensure their success in production. Join our community to learn how your peers are adopting KMP. Once suspended, touchlab will not be able to comment or publish posts until their suspension is removed. Once unsuspended, touchlab will be able to comment and publish posts again. Once unpublished, all posts by touchlab will become hidden and only accessible to themselves. If touchlab is not suspended, they can still re-publish their posts from their dashboard. Note: Once unpublished, this post will become invisible to the public and only accessible to Jigar Brahmbhatt. They can still re-publish the post if they are not suspended. Thanks for keeping DEV Community safe. Here is what you can do to flag touchlab: touchlab consistently posts content that violates DEV Community's code of conduct because it is harassing, offensive or spammy. Unflagging touchlab will restore default visibility to their posts. DEV Community — A constructive and inclusive social network for software developers. With you every step of your journey. Built on Forem — the open source software that powers DEV and other inclusive communities.Made with love and Ruby on Rails. DEV Community © 2016 - 2023. We're a place where coders share, stay up-to-date and grow their careers.



This post first appeared on VedVyas Articles, please read the originial post: here

Share the post

Optimizing Gradle Builds in Multi-module Projects

×

Subscribe to Vedvyas Articles

Get updates delivered right to your inbox!

Thank you for your subscription

×