Tutorials
This expanded tutorial shows extended concepts about using Buck to build a project after you have installed Buck, including creating a project, building a project, packaging a project, etc.
Currently this tutorial is Android specific for either Mac or Linux. We will be adding iOS, Java and Windows specific tutorial information in the near future.
Path Setup
Add Buck to your $PATH
and set up buckd
:
sudo ln -s ${PWD}/bin/buck /usr/bin/buck sudo ln -s ${PWD}/bin/buckd /usr/bin/buckd
Create Project
We are going to build a sample application. We should start our project in an empty directory, so create a new one and navigate to it:
mkdir -p ~/my-first-buck-project/ cd ~/my-first-buck-project/
Note: the following instructions will now assume that all commands are run from your ~/my-first-buck-project
directory.
Compile Your Code
Android applications are typically written in Java and kotlin, so the first thing we will do is to configure Buck to compile code against the Android API. To do so, Buck needs to know where your Android SDK is. Assuming that your Android SDK is installed in ~/android-sdk
, run the following command to set a ANDROID_SDK
environment variable that tells Buck where to find your Android SDK:
export ANDROID_SDK=$HOME/android-sdk
Now that Buck can locate your Android SDK, it is time to compile some Java code. First, we create a simple Activity
at java/com/example/activity/MyFirstActivity.java
:
mkdir -p java/com/example/activity/ echo "package com.example.activity; import android.app.Activity; import android.os.Bundle; public class MyFirstActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } }" > java/com/example/activity/MyFirstActivity.java
Now we need a build file that defines a build rule to compile this Java code, so we create an android_library()
rule in java/com/example/activity/BUCK
:
echo "android_library( name = 'activity', srcs = glob(['*.java']), visibility = [ 'PUBLIC' ], )" > java/com/example/activity/BUCK
Now we can compile our Java code using Buck:
buck build //java/com/example/activity:activity
Buck generates its output in thebuck-out
directory, so this is a good time to specifybuck-out
as something that should be ignored by your version control system.
Now that Buck can locate your Android SDK, it is time to compile some kotlin code. First, we create a simple Activity
at kotlin/com/example/activity/MyFirstActivity.kt
:
mkdir -p kotlin/com/example/activity/ echo "package com.example.activity import android.app.Activity import android.os.Bundle class MyFirstActivity : Activity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) } }" > kotlin/com/example/activity/MyFirstActivity.kt
Now we need a build file that defines a build rule to compile this kotlin code, so we create an android_library()
rule in kotlin/com/example/activity/BUCK
:
echo "android_library( name = 'activity', srcs = glob(['*.kt']), language = "KOTLIN", visibility = [ 'PUBLIC' ], )" > kotlin/com/example/activity/BUCK
Now we can compile our Java code using Buck:
buck build //kotlin/com/example/activity:activity
Buck generates its output in thebuck-out
directory, so this is a good time to specifybuck-out
as something that should be ignored by your version control system.
First, we create rust source files and directories:
mkdir -p src/front_of_house echo "mod front_of_house; pub use crate::front_of_house::hosting; pub use crate::front_of_house::serving; fn main() { hosting::add_to_waitlist(); hosting::seat_at_table(); serving::take_order(); serving::serve_order(); serving::take_payment(); }" > src/main.rs echo "pub mod hosting; pub mod serving;" > src/front_of_house.rs echo "pub fn add_to_waitlist() { println!(\"Added to watinglist.\"); } pub fn seat_at_table() { println!(\"Seated at table.\"); }" > src/front_of_house/hosting.rs echo "pub fn take_order() { println!(\"Ordered.\"); } pub fn serve_order() { println!(\"Order served.\"); } pub fn take_payment() { println!(\"Payment done.\"); }" > src/front_of_house/serving.rs
Now we need a build file that defines a build rule to compile this rust code, so we create an rust_binary()
rule in BUCK
:
echo "rust_binary( name = 'restaurant', srcs = glob( ['src/**/*.rs'], ), )" >BUCK
Now we can build our rust code using Buck:
buck build :restaurant
And run the sample:
buck run :restaurant
Buck generates its output in thebuck-out
directory, so this is a good time to specifybuck-out
as something that should be ignored by your version control system.
Package Resources
Android applications frequently contain resources, such as strings and images. For this example, we will create a trivial Android resource bundle that contains a single string:
mkdir -p res/com/example/activity/res/values/ echo "<?xml version='1.0' encoding='utf-8' ?> <resources> <string name='app_name'>Hello World</string> </resources>" > res/com/example/activity/res/values/strings.xml
Buck needs a way to reference this collection of resources, so we need to create a build file that defines an android_resource
rule:
echo "android_resource( name = 'res', res = subdir_glob([('res', '**')]), package = 'com.example', visibility = [ '//apps/myapp:', ], )" > res/com/example/activity/BUCK
Create a Keystore
In practice, you will want to be able to test your Android app on a physical Android device, which means that it needs to be signed. We will create app-specific information, such as the key and manifest, in its own directory to keep things tidy:
mkdir -p apps/myapp/
To keep things simple, we will create a self-signed certificate for debugging.
Unfortunately, this is not a one-liner because there is a number of prompts from the keytool
command.
keytool -genkey -keystore apps/myapp/debug.keystore -alias my_alias \ -keyalg RSA -keysize 2048 -validity 10000
When prompted for a keystore password, just use android
(and then type it again to confirm it), and hit Enter
to accept the default values for name, organizational unit, etc.
Then create a .properties
file that stores all of this information:
echo "key.alias=my_alias key.store.password=android key.alias.password=android" > apps/myapp/debug.keystore.properties
Build an APK
An Android application needs a manifest named AndroidManifest.xml
, so we must create such a file:
echo "<?xml version='1.0' encoding='utf-8'?> <manifest xmlns:android='http://schemas.android.com/apk/res/android' package='com.example' > <application android:label='@string/app_name' android:hardwareAccelerated='true'> <activity android:name='.activity.MyFirstActivity'> <intent-filter> <action android:name='android.intent.action.MAIN' /> <category android:name='android.intent.category.LAUNCHER' /> </intent-filter> </activity> </application> </manifest>" > apps/myapp/AndroidManifest.xml
Now we define an android_binary
and keystore
rule in our build file:
echo "android_binary( name = 'app', manifest = 'AndroidManifest.xml', manifest_entries = { 'version_code': 1, 'version_name': '1.0', 'min_sdk_version': 26, 'target_sdk_version': 29 }, keystore = ':debug_keystore', deps = [ '//java/com/example/activity:activity', '//res/com/example/activity:res', ], ) keystore( name = 'debug_keystore', store = 'debug.keystore', properties = 'debug.keystore.properties', )" > apps/myapp/BUCK
Building an android_binary
rule will produce an APK:
buck build //apps/myapp:app
Alternatively, if you have an Android device connected to your computer, you can build and install the APK in one step with buck install
:
buck install //apps/myapp:app
Create an Alias
Typing buck build //apps/myapp:app
every time you want to rebuild your APK can be tedious. Fortunately, Buck makes it possible to define an alias for a build target. An alias can always be used in place of a build target when using Buck's command-line interface.
Aliases must be defined in the [alias]
a config file in the root of the project:
echo "[alias] app = //apps/myapp:app" > .buckconfig
With this alias in place, the command to build and install the APK is much shorter and easier to remember:
buck install app
Create an IntelliJ Project
You likely want to develop your Android app using an IDE. Fortunately, Buck can generate an IntelliJ project from the build rules you defined in your build files.
In order to ensure that IntelliJ recognizes where your Java folders are, you need to specify the [java].src_roots
in your .buckconfig
file:
echo "[java] src_roots = /java/" >> .buckconfig
Now you can create the IntelliJ project by running buck project
:
buck project --ide intellij
Note that you will likely want to exclude these generated files from version control, so add the following to your .gitignore
file (or .hgignore
if you are using Mercurial) along with the files generated by buckd
:
echo "/.buckd /buck-out *.iml /.idea/compiler.xml /.idea/libraries/*.xml /.idea/modules.xml /.idea/runConfigurations/Debug_Buck_test.xml" > .gitignore
Now you can build your Android application from either IntelliJ or the command line.