Gradle is an awesome build system which makes my life as a developer much easier. However, with large numbers of dependencies build times can slow to a snail’s pace, leaving developers frustrated and legitimately slacking off.

okbuck gradle plugin android

Buck

Facebook has a tool that can help many developers emerge from this time-suck. The tool is the Buck build system. Buck is built to encourage developers to create and use small and reusable modules of code. Buck has many advantages over Gradle, the most beneficial of which are support for incremental builds and shorter build times.

I’m going to walk through first steps with okbuck to get started using it with an Android project. It’s easy to configure, and it doesn’t affect Android Gradle builds, so there’s no downside to experimenting with it.

Related: Our most popular post on Android – Replace AsyncTask and AsyncTaskLoader with Rx.Observable – RxJava Android Patterns

Buck overview

Buck generates rules based on your build’s dependencies and creates a Directed Acyclic Graph (DAG) from the rules. When a build is kicked off, it builds rules starting with the leaf nodes of the DAG. The rules are added to a queue and built when a thread is available. If a rule is successfully built, other rules that depend on it check if their dependencies are satisfied and if so, get added to the queue. This process continues until all nodes have been built.

Output from building nodes is cached to prevent the churn that Gradle presently incurs when a build is kicked off. When Buck begins building a rule, the cache is checked for previous outputs and if the output exists it is used instead of building it locally. Buck hashes the rule to create a cache key and will rebuild any rules whose key has changed preventing the need to clean the build. You can also set up Buck to use a cache that will be committed to your source control which will improve build speeds throughout your process: on developer’s machines and on continuous integration (CI), but that’s outside the scope of this blog.

For Android builds, Buck includes a customized version of the Android DX build tool (creates Dalvik Executable .dex files from Java .class files) that includes performance improvements like running multiple copies of DX concurrently and faster dex merging.

Build Rules

A build rule uses a set of input files to generate zero or one output files. Buck includes some built-in build rules for common procedures in a few major languages. In Android, for example, it’s common to build a Java library against the Android SDK as well as to produce an APK file. These rules are android_library and android_binary respectively. Build rules must have at least three arguments: the name of the build rule, the rule’s dependencies, and the set of build rules that are allowed to claim the rule as a dependency.

Build File

Buck uses a build file named BUCK which defines build rules. Build rules are defined using Python functions in a build file. This means that developers can define their own Python functions within a build file to add something to the build process. Source files can only be referred to by rules in the nearest build file with respect to the project’s file tree.

OkBuck

Buck configuration is verbose and time consuming. Quite ironic for a tool that speeds up Android builds significantly. To take the pain out of using Buck, Uber developed the Gradle plugin okbuck. The plugin adds a couple of tasks to the Gradle project that makes using Buck significantly easier. These tasks generate a Buck wrapper, similar in fashion to the Gradle wrapper most Android developers are familiar with. okbuck also takes care of generating all of the Buck configuration based on Gradle project you’re already using.

Some developers will find that using okbuck will help them locally, but won’t want to use it on CI. Have it your way! okbuck supplements Gradle and the two can be used on the same project. okbuck can just be ignored if you don’t want to use it, but it does need to be added to your Gradle project in order to be used.

Installation

I’m assuming that you use Homebrew for the installation portion of this blog. If you’re not using Homebrew, please take a moment to learn about it and consider whether it will help you be more productive.

  • Install Buck (optional)

If you want to play with Buck outside of a Gradle project, install Buck and go to town. okbuck (via the buckw wrapper) will download Buck if isn’t available.

brew update  
brew tap facebook/fb  
brew install buck
  • Prerequisites

You’ll want to configure the okbuck plugin for your Gradle project, which is quite easy.

Install a few tools

brew install android-ndk ant  
brew install watchman

Installing the android-ndk formula via Homebrew is not necessary if you have an Android NDK installation elsewhere. Just be certain that the ANDROID_NDK environment variable points to your NDK installation.

  • Configure

Configuring your Gradle project to use okbuck is simple. Add a classpath dependency and apply the plugin in your top-level build.gradle file, done.

buildscript {  
    repositories {  
        jcenter()  
    }
    dependencies {  
        classpath 'com.uber:okbuck:0.10.0'  
    }
}

apply plugin: 'com.uber.okbuck'
  • Ensure your project’s Gradle version is compliant.

At the time of this writing, the minimum supported Gradle version is 2.14.1. Just edit the distributionUrl property in {project}/gradle/wrapper/gradle-wrapper.properties and change to gradle–2.14.1-all.zip. Gradle will fail and issue a message that tells you what your currently configured version is and what the present minimum required version is.

  • Generate the Buck wrapper

okbuck will generate a Buck wrapper similar in function to the Gradle wrapper that most developers are likely familiar with: gradlew

./gradlew :buckWrapper
  • Configure code signing

If you try to skip this step and build with the new Buck wrapper, you’ll quickly encounter this error.

Execution failed for task ':okbuck'.  
> release of app has no signing config set!

okbuck requires that you set up your signing config, which is a good idea anyway. Generate a keystore and configure your build appropriately.

signingConfigs {  
    release {  
        storeFile file(RELATIVE_PATH_TO_YOUR_KEYSTORE)  
        storePassword YOUR_STORE_PASSWORD  
        keyAlias YOUR_KEY_ALIAS  
        keyPassword YOUR_KEY_PASSWORD  
    }
}  
buildTypes {  
    release {  
        signingConfig signingConfigs.release  
        minifyEnabled false  
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'  
    }
}   

For the purposes of writing this blog, I cheated and just used the default debug keystore to sign my release build. Don’t do this unless your project is a throw-away sandbox like mine was.

buildTypes {  
    release {  
        signingConfig signingConfigs.debug  
        minifyEnabled false  
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'  
    }
}
  • Build with Buck

Building with the Buck wrapper is easy.

./buckw build //app:bin_debug

It’s even easier if you use an alias.

./buckw build appDebug

Aliases are defined in the .buckconfig file., okbuck will create some default aliases in the local version of the file, .buckconfig.local

[alias]  
        appDebug = //app:bin_debug  
        appRelease = //app:bin_release
  • Install/run with Buck

Installing with the Buck wrapper is just as easy, you can launch the app by tacking on the --run flag.

./buckw install --run appDebug

This should get you started down a road to faster builds and learning more about Buck. There is a lot more to learn about Buck and I encourage you to visit https://buckbuild.com/ if you are interested in modifying the buck configuration files that okbuck created for you.

Some of okbuck’s currently unsupported features (Kotlin support, data binding) might be a deal breaker for some projects. Support for those features is planned for the future so don’t lose hope.

  

Leave a Reply

Your email address will not be published. Required fields are marked *