diff options
Diffstat (limited to 'site/docs/tutorial')
-rw-r--r-- | site/docs/tutorial/android-app.md | 280 | ||||
-rw-r--r-- | site/docs/tutorial/app.md | 45 | ||||
-rw-r--r-- | site/docs/tutorial/backend-server.md | 224 | ||||
-rw-r--r-- | site/docs/tutorial/cpp.md | 360 | ||||
-rw-r--r-- | site/docs/tutorial/environment.md | 91 | ||||
-rw-r--r-- | site/docs/tutorial/ios-app.md | 206 | ||||
-rw-r--r-- | site/docs/tutorial/java.md | 245 | ||||
-rw-r--r-- | site/docs/tutorial/review.md | 29 | ||||
-rw-r--r-- | site/docs/tutorial/workspace.md | 53 |
9 files changed, 1515 insertions, 18 deletions
diff --git a/site/docs/tutorial/android-app.md b/site/docs/tutorial/android-app.md index ea52e3ef1d..31e86475cc 100644 --- a/site/docs/tutorial/android-app.md +++ b/site/docs/tutorial/android-app.md @@ -1,4 +1,280 @@ --- -layout: redirect -redirect: docs/tutorial/android-app.html +layout: documentation +title: Tutorial - Build an Android App --- + +# Tutorial - Build an Android App + +The sample Android app in this tutorial is a very simple application that makes +an HTTP connection to the [backend server](backend-server.md) and displays the +resulting response. + +Here, you'll do the following: + +* Review the source files for the app +* Update the `WORKSPACE` file +* Create a `BUILD` file +* Run the build +* Find the build outputs +* Run the app + +## Review the source files + +Let's take a look at the source files for the app. These are located in +`$WORKSPACE/android/`. + +The key files and directories are: + +<table class="table table-condensed table-striped"> +<thead> +<tr> +<td>Name</td> +<td>Location</td> +</tr> +</thead> +<tbody> +<tr> +<td>Manifest file</td> +<td><code>src/main/java/com/google/bazel/example/android/AndroidManifest.xml</code></td> +</tr> +<tr> +<td>Activity source file</td> +<td><code>src/main/java/com/google/bazel/example/android/activities/MainActivity.java</code></td> +</tr> +<tr> +<td>Resource file directory</td> +<td><code>src/main/java/com/google/bazel/example/android/res/</code></td> +</tr> +</tbody> +</table> + +Note that you're just looking at these files now to become familiar with the +structure of the app. You don't have to edit any of the source files to complete +this tutorial. + +## Update the WORKSPACE file + +Bazel needs to run the Android SDK +[build tools](https://developer.android.com/tools/revisions/build-tools.html) +and uses the SDK libraries to build the app. This means that you need to add +some information to your `WORKSPACE` file so that Bazel knows where to find +them. Note that this step is not required when you build for other platforms. +For example, Bazel automatically detects the location of Java, C++ and +Objective-C compilers from settings in your environment. + +Add the following lines to your `WORKSPACE` file: + +```python +android_sdk_repository( + name = "androidsdk", + # Replace with path to Android SDK on your system + path = "/Users/username/Library/Android/sdk", + # Replace with the Android SDK API level + api_level = 23, + # Replace with the version in sdk/build-tools/ + build_tools_version="23.0.0" +) +``` + +**Optional:** This is not required by this tutorial, but if you want to compile +native code into your Android app, you also need to download the +[Android NDK](https://developer.android.com/ndk/downloads/index.html) and +tell Bazel where to find it by adding the following rule to your `WORKSPACE` +file: + +```python +android_ndk_repository( + name = "androidndk", + # Replace with path to Android NDK on your system + path = "/Users/username/Library/Android/ndk", + # Replace with the Android NDK API level + api_level = 21 +) +``` + +`api_level` is the version of the Android API the SDK and the NDK target +(for example, 19 for Android K and 21 for Android L). It's not necessary to set +the API levels to the same value for the SDK and NDK. +[This web page](https://developer.android.com/ndk/guides/stable_apis.html) +contains a map from Android releases to NDK-supported API levels. + +## Create a BUILD file + +A [`BUILD` file](/docs/build-ref.html#BUILD_files) is a text file that describes +the relationship between a set of build outputs -- for example, compiled +software libraries or executables -- and their dependencies. These dependencies +may be source files in your workspace or other build outputs. `BUILD` files are +written in the Bazel *build language*. + +`BUILD` files are part of concept in Bazel known as the *package hierarchy*. +The package hierarchy is a logical structure that overlays the directory +structure in your workspace. Each [package](/docs/build-ref.html#packages) is a +directory (and its subdirectories) that contains a related set of source files +and a `BUILD` file. The package also includes any subdirectories, excluding +those that contain their own `BUILD` file. The *package name* is the name of the +directory where the `BUILD` file is located. + +Note that this package hierarchy is distinct from, but coexists with, the Java +package hierarchy for your Android app. + +For the simple Android app in this tutorial, we'll consider all the source files +in `$WORKSPACE/android/` to comprise a single Bazel package. A more complex +project may have many nested packages. + +At a command-line prompt, open your new `BUILD` file for editing: + +```bash +$ vi $WORKSPACE/android/BUILD +``` + +### Add an android_library rule + +A `BUILD` file contains several different types of instructions for Bazel. The +most important type is the [build rule](/docs/build-ref.html#funcs), which tells +Bazel how to build an intermediate or final software output from a set of source +files or other dependencies. + +Bazel provides two build rules, `android_library` and `android_binary`, that you +can use to build an Android app. For this tutorial, you'll first use the +[`android_library`](/docs/be/android.html#android_library) rule to tell +Bazel how to build an +[Android library module](http://developer.android.com/tools/projects/index.html#LibraryProjects) +from the app source code and resource files. Then you'll use the +`android_binary` rule to tell it how to build the Android application package. + +Add the following to your `BUILD` file: + +```python +android_library( + name = "activities", + srcs = glob(["src/main/java/com/google/bazel/example/android/activities/*.java"]), + custom_package = "com.google.bazel.example.android.activities", + manifest = "src/main/java/com/google/bazel/example/android/activities/AndroidManifest.xml", + resource_files = glob(["src/main/java/com/google/bazel/example/android/activities/res/**"]), +) +``` + +As you can see, the `android_library` build rule contains a set of attributes +that specify the information that Bazel needs to build a library module from the +source files. Note also that the name of the rule is `activities`. You'll +reference the rule using this name as a dependency in the `android_binary` rule. + +### Add an android_binary rule + +The [`android_binary`](/docs/be/android.html#android_binary) rule builds +the Android application package (`.apk` file) for your app. + +Add the following to your build file: + +```python +android_binary( + name = "android", + custom_package = "com.google.bazel.example.android", + manifest = "src/main/java/com/google/bazel/example/android/AndroidManifest.xml", + resource_files = glob(["src/main/java/com/google/bazel/example/android/res/**"]), + deps = [":activities"], +) +``` + +Here, the `deps` attribute references the output of the `activities` rule you +added to the `BUILD` file above. This means that, when Bazel builds the output +of this rule, it checks first to see if the output of the `activities` library +rule has been built and is up-to-date. If not, it builds it and then uses that +output to build the application package file. + +Now, save and close the file. You can compare your `BUILD` file to the +[completed example](https://github.com/bazelbuild/examples/blob/master/tutorial/android/BUILD) +in the `master` branch of the GitHub repo. + +## Run the build + +You use the +[`bazel`](/docs/bazel-user-manual.html) command-line tool to run builds, execute +unit tests and perform other operations in Bazel. This tool is located in the +`output` subdirectory of the location where you installed Bazel. During +[installation](/docs/install.md), you probably added this location to your +path. + +Before you build the sample app, make sure that your current working directory +is inside your Bazel workspace: + +```bash +$ cd $WORKSPACE +``` + +Now, enter the following to build the sample app: + +```bash +$ bazel build //android:android +``` + +The [`build`](/docs/bazel-user-manual.html#build) subcommand instructs Bazel to +build the target that follows. The target is specified as the name of a build +rule inside a `BUILD` file, with along with the package path relative to +your workspace directory. Note that you can sometimes omit the package path +or target name, depending on your current working directory at the command +line and the name of the target. See [Labels](/docs/build-ref.html#labels) in +*Bazel Concepts and Terminology* page for more information about target labels +and paths. + +Bazel now launches and builds the sample app. During the build process, its +output will appear similar to the following: + +```bash +INFO: Found 1 target... +Target //android:android up-to-date: + bazel-bin/android/android_deploy.jar + bazel-bin/android/android_unsigned.apk + bazel-bin/android/android.apk +INFO: Elapsed time: 7.237s, Critical Path: 5.81s +``` + +## Find the build outputs + +Bazel stores the outputs of both intermediate and final build operations in +a set of per-user, per-workspace output directories. These directories are +symlinked from the following locations: + +* `$WORKSPACE/bazel-bin`, which stores binary executables and other runnable + build outputs +* `$WORKSPACE/bazel-genfiles`, which stores intermediary source files that are + generated by Bazel rules +* `$WORKSPACE/bazel-out`, which stores other types of build outputs + +Bazel stores the Android `.apk` file generated using the `android_binary` rule +in the `bazel-bin/android/` directory, where the subdirectory name `android` is +derived from the name of the Bazel package. + +At a command prompt, list the contents of this directory and find the +`android.apk` file: + +```bash +$ ls $WORKSPACE/bazel-bin/android +``` + +## Run the app + +You can now deploy the app to a connected Android device or emulator from the +command line using the +[`bazel mobile-install`](http://bazel.io/docs/bazel-user-manual.html#mobile-install) +command. This command uses the Android Debug Bridge (`adb`) to communicate with +the device. You must set up your device to use `adb` following the instructions +in +[Android Debug Bridge](http://developer.android.com/tools/help/adb.html) before +deployment. + +Enter the following: + +```bash +$ bazel mobile-install //android:android +``` + +Note that the `mobile-install` subcommand also supports the +[`--incremental`](http://bazel.io/docs/bazel-user-manual.html#mobile-install) +flag that can be used to deploy only those parts of the app that have changed +since the last deployment. + +## What's next + +Now that you've built a sample app for Android, it's time to do the same for +the [iOS app](ios-app.md). diff --git a/site/docs/tutorial/app.md b/site/docs/tutorial/app.md index d3c2872f6f..fdc33c5f83 100644 --- a/site/docs/tutorial/app.md +++ b/site/docs/tutorial/app.md @@ -1,4 +1,45 @@ --- -layout: redirect -redirect: docs/tutorial/app.html +layout: documentation +title: Build Mobile Application --- + +# Build Mobile Application + +You can use Bazel to build a variety of software outputs, including +Linux and Mac OS X applications written in Java, C++ and Objective-C. You can +also use Bazel to build software for other platforms or written in other +languages. + +This tutorial shows how to use Bazel to build the following: + +* An Android app +* An iOS app +* A mobile backend server running on App Engine + +In this tutorial, you'll learn how to: + +* Set up a Bazel workspace and create a `WORKSPACE` file +* Create `BUILD` files that contain the instructions used by Bazel to build + the software +* Run builds using the Bazel command line tool + +## Requirements + +You can follow the steps in this tutorial on either a Linux or Mac OS X system. +However, you can only build the iOS app if you are running Bazel on OS X. If +you are using Linux, you can skip the iOS instructions and still complete +the rest of the tutorial steps. + +## Sample project + +You don't have to write your own mobile apps and backend server to use this +tutorial. Instead, you'll use a sample project hosted on GitHub. The sample +project is hosted at the following location: + +[https://github.com/bazelbuild/examples/](https://github.com/bazelbuild/examples/) + +You'll grab the sample project files in the next step in this tutorial. + +## What's next + +Let's start off by [setting up](environment.md) the tutorial environment. diff --git a/site/docs/tutorial/backend-server.md b/site/docs/tutorial/backend-server.md index 150f9152ec..ad668a0d3b 100644 --- a/site/docs/tutorial/backend-server.md +++ b/site/docs/tutorial/backend-server.md @@ -1,4 +1,224 @@ --- -layout: redirect -redirect: docs/tutorial/backend-server.html +layout: documentation +title: Tutorial - Build the Backend Server --- + +# Tutorial - Build the Backend Server + +The backend server is a simple web application that runs on Google App Engine +and responds to incoming HTTP requests from the sample Android and iOS apps. + +Here, you'll do the following: + +* Review the source files for the app +* Update the `WORKSPACE` file +* Create the `appengine.BUILD` file +* Create a `BUILD` file +* Run the build +* Find the build outputs +* Deploy to a local development server +* Deploy to Google App Engine + +Bazel provides a set of [App Engine build rules](/docs/be/appengine.html) +written using the [Skylark](/docs/skylark/index.html) framework. You'll use +these in the steps below to build the application. + +## Review the source files + +The source files for the backend server are located in `$WORKSPACE/backend/`. + +The key files and directories are: + +<table class="table table-condensed table-striped"> +<thead> +<tr> +<td>Name</td> +<td>Location</td> +</tr> +</thead> +<tbody> +<tr> +<td>Source file directory</td> +<td><code>src/main/java/com/google/bazel/example/app/</code></td> +</tr> +<tr> +<td>Web application metadata directory</td> +<td><code>webapp/WEB-INF/</code></td> +</tr> +</tbody> +</table> + +## Update the WORKSPACE file + +As with the Android app, you must add references to +[external dependencies](http://bazel.io/docs/external.html) to your `WORKSPACE` +file. For the backend server, these are references to the App Engine SDK, +the Java Servlet SDK and other libraries needed to build the App Engine +applications. + +### Add a new\_http\_archive rule + +When you built the Android app, you added a reference to the location on your +filesystem where you downloaded and installed the Android SDK. For the +backend server, however, you'll give Bazel instructions for downloading the +required App Engine SDK package from a remote server. This is optional. You +can also download and install the SDK manually on your filesystem and reference +it from that location as described in the +[App Engine rule documentation](/docs/be/appengine.html). + +Add the following to your `WORKSPACE` file: + +```python +git_repository( + name = "io_bazel_rules_appengine", + remote = "https://github.com/bazelbuild/rules_appengine.git", + tag = "0.0.2", +) +load("@io_bazel_rules_appengine//appengine:appengine.bzl", "appengine_repositories") +appengine_repositories() +``` + +[`git_repository`](/docs/be/workspace.html#git_repository) downloads the +AppEngine rules from GitHub, then the next two lines use the +`appengine_repositories` function defined in these rules to download the +libraries and SDK needed to build AppEngine applications. + +Now, save and close the file. You can compare your `WORKSPACE` file to the +[completed example](https://github.com/bazelbuild/examples//blob/master/tutorial/WORKSPACE) +in the `master` branch of the GitHub repo. + +## Create a BUILD file + +Now that you have set up the external dependencies, you can go ahead and create +the `BUILD` file for the backend server, as you did previously for the sample +Android and iOS apps. + +Open your new `BUILD` file for editing: + +```bash +$ vi $WORKSPACE/backend/BUILD +``` + +### Add a java_binary rule + +Add the following to your `BUILD` file: + +```python +java_binary( + name = "app", + srcs = glob(["src/main/java/**/*.java"]), + main_class = "does.not.exist", + deps = [ + "@io_bazel_rules_appengine//appengine:javax.servlet.api", + ], +) +``` + +The [`java_binary`](/docs/be/java.html#java_binary) tells Bazel +how to build a Java `.jar` library for your application, plus a wrapper shell +script that launches the application code from the specified main class. Here, +we're using this rule instead of the +[`java_library`](/docs/be/java.html#java_library) because we need +the `.jar` file to contain all the dependencies required to build the final +App Engine `.war` file. For this reason, we specify a bogus class name +for the `main_class` attribute. + +### Add an appengine_war rule + +Add the following to your `BUILD` file: + +```python +load("@io_bazel_rules_appengine//appengine:appengine.bzl", "appengine_war") + +appengine_war( + name = "backend", + data = [":webapp"], + data_path = "/backend/webapp", + jars = [":app_deploy.jar"], +) + +filegroup( + name = "webapp", + srcs = glob(["webapp/**/*"]), +) +``` + +The [`appengine_war`](/docs/be/appengine.html#appengine_war) +rule builds the final App Engine `war` file from the library `.jar` file and web +application metadata files in the `webapp` directory. + +Save and close the file. Again, the +[completed example](https://github.com/google/bazel-examples/blob/master/tutorial/backend/BUILD) +is in the `master` branch of the GitHub repo. + +## Run the build + +Make sure that your current working directory is inside your Bazel workspace: + +```bash +$ cd $WORKSPACE +``` + +Now, enter the following to build the sample app: + +```bash +$ bazel build //backend:backend +``` + +Bazel now launches and builds the sample app. During the build process, its +output will appear similar to the following: + +```bash +INFO: Found 1 target... +Target //backend:backend up-to-date: + bazel-bin/backend/backend.war + bazel-bin/backend/backend.deploy + bazel-bin/backend/backend +INFO: Elapsed time: 56.867s, Critical Path: 2.72s +``` + +## Find the build outputs + +The `.war` file and other outputs are located in the +`$WORKSPACE/bazel-bin/backend` directory. + +## Deploy to a local development server + +The `appengine_war` rule generates an upload script that you can use to deploy +your backend server on Google App Engine. Here, you'll start a local App Engine +development server in your environment and deploy your application there. + +To deploy the application, enter the following: + +```bash +$ bazel-bin/backend/backend --port=12345 +``` + +Your application URL will be `http://localhost:12345` + +## Deploy to Google App Engine + +You can also deploy the application to the live App Engine serving +environment on Google Cloud Platform. For this scenario, you must first create +a project in the +[Google Developers Console](https://console.developers.google.com). + +To deploy the application, enter the following: + +```bash +$ $WORKSPACE/bazel-bin/backend/backend.deploy <project-id> +``` + +The deployment script prompts you to authorize access to Google Cloud Platform. +After you have authorized access the first time, you can deploy the application +using the `bazel` command and the following rule target: + +```bash +$ bazel run //backend:backend.deploy <project-id> +``` + +Your application URL will be `http://<project-id>.appspot.com`. + +## What's next + +Now let's [review](review.md) the tutorial steps. diff --git a/site/docs/tutorial/cpp.md b/site/docs/tutorial/cpp.md index 6ec737f93d..3d6effbd68 100644 --- a/site/docs/tutorial/cpp.md +++ b/site/docs/tutorial/cpp.md @@ -1,4 +1,360 @@ --- -layout: redirect -redirect: docs/tutorial/cpp.html +layout: documentation +title: Build C++ --- + +Build C++ +========= + +You can use Bazel to build your C++ application. In this tutorial you'll learn how to: + +* Build your first C++ target +* Use external libraries +* Write and run C++ tests +* Use precompiled libraries + +## Setting up your workspace + +Suppose that you have an existing project in a directory, say, +`~/gitroot/my-project/`. Create an empty file at +`~/gitroot/my-project/WORKSPACE` to show Bazel where your project's root is. +We are going to create a small hello world project with the following directory structure: +{% highlight bash %} +└── my-project + ├── lib + │ ├── BUILD + │ ├── hello-greet.cc + │ └── hello-greet.h + ├── main + │ ├── BUILD + │ ├── hello-time.cc + │ ├── hello-time.h + │ └── hello-world.cc + └── WORKSPACE +{% endhighlight %} + +## Creating source files + +Using the following commands to create the necessary source files: +{% highlight bash %} +$ # If you're not already there, move to your workspace directory. +$ cd ~/gitroot/my-project +$ mkdir ./main +$ cat > main/hello-world.cc <<'EOF' +#include "lib/hello-greet.h" +#include "main/hello-time.h" +#include <iostream> +#include <string> + +int main(int argc, char** argv) { + std::string who = "world"; + if (argc > 1) { + who = argv[1]; + } + std::cout << get_greet(who) <<std::endl; + print_localtime(); + return 0; +} +EOF +$ cat > main/hello-time.h <<'EOF' +#ifndef MAIN_HELLO_TIME_H_ +#define MAIN_HELLO_TIME_H_ + +void print_localtime(); + +#endif +EOF +$ cat > main/hello-time.cc <<'EOF' +#include "main/hello-time.h" +#include <ctime> +#include <iostream> + +void print_localtime() { + std::time_t result = std::time(nullptr); + std::cout << std::asctime(std::localtime(&result)); +} +EOF +$ mkdir ./lib +$ cat > lib/hello-greet.h <<'EOF' +#ifndef LIB_HELLO_GREET_H_ +#define LIB_HELLO_GREET_H_ + +#include <string> + +std::string get_greet(const std::string &thing); + +#endif +EOF +$ cat > lib/hello-greet.cc <<'EOF' +#include "lib/hello-greet.h" +#include <string> + +std::string get_greet(const std::string& who) { + return "Hello " + who; +} +EOF +{% endhighlight %} + +## Adding BUILD files + +As you can see from the source code, `main/hello-world.cc` needs to include both `lib/hello-greet.h` and `main/hello-time.h`. +First we create `lib/BUILD` for hello-greet.cc: + +{% highlight python %} +cc_library( + name = "hello-greet", + srcs = ["hello-greet.cc"], + hdrs = ["hello-greet.h"], + visibility = ["//main:__pkg__"], +) +{% endhighlight %} + +Note that `visibility = ["//main:__pkg__"]` indicates `hello-greet` is visible from `main/BUILD`. +Then we'd create the following `main/BUILD` file: + +{% highlight python %} +cc_library( + name = "hello-time", + srcs = ["hello-time.cc"], + hdrs = ["hello-time.h"], +) + +cc_binary( + name = "hello-world", + srcs = ["hello-world.cc"], + deps = [ + ":hello-time", + "//lib:hello-greet", + ], +) +{% endhighlight %} + +Note when depending on a target in the same package, we can just use `:hello-time`. +When the target is in other package, a full path from root should be used, like `//lib:hello-greet`. + +Now you are ready to build your hello world C++ binary: + +{% highlight bash %} +$ bazel build main:hello-world +INFO: Found 1 target... +Target //main:hello-world up-to-date: + bazel-bin/main/hello-world +INFO: Elapsed time: 2.869s, Critical Path: 1.00s +$ ./bazel-bin/main/hello-world +Hello world +Thu Jun 23 18:51:46 2016 +$ ./bazel-bin/main/hello-world Bazel +Hello Bazel +Thu Jun 23 18:52:10 2016 +{% endhighlight %} + +Congratulations, you've just built your first Bazel target! + +## Transitive includes + +If a file includes a header, then the file's rule should depend on that header's +library. Conversely, only direct dependencies need to be specified as +dependencies. For example, suppose `sandwich.h` includes `bread.h` and +`bread.h` includes `flour.h`. `sandwich.h` doesn't include `flour.h` (who wants +flour in their sandwich?), so the BUILD file would look like: + +```python +cc_library( + name = "sandwich", + srcs = ["sandwich.cc"], + hdrs = ["sandwich.h"], + deps = [":bread"], +) + +cc_library( + name = "bread", + srcs = ["bread.cc"], + hdrs = ["bread.h"], + deps = [":flour"], +) + +cc_library( + name = "flour", + srcs = ["flour.cc"], + hdrs = ["flour.h"], +) +``` + +Here, the `sandwich` library depends on the `bread` library, which depends +on the `flour` library. + +## Adding include paths + +Sometimes you cannot (or do not want to) base include paths at the workspace +root. Existing libraries might already have a include directory that doesn't +match its path in your workspace. For example, suppose you have the following +directory structure: + +``` +└── my-project + ├── third_party + │ └── some_lib + │ ├── BUILD + │ ├── include + │ │ └── some_lib.h + │ └── some_lib.cc + └── WORKSPACE +``` + +Bazel will expect `some_lib.h` to be included as +`third_party/some_lib/include/some_lib.h`, but suppose `some_lib.cc` includes +`"include/some_lib.h"`. To make that include path valid, +`third_party/some_lib/BUILD` will need to specify that the `some_lib/` +directory is an include directory: + +```python +cc_library( + name = "some_lib", + srcs = ["some_lib.cc"], + hdrs = ["some_lib.h"], + copts = ["-Ithird_party/some_lib"], +) +``` + +This is especially useful for external dependencies, as their header files +must otherwise be included with an `external/[repository-name]/` prefix. + +## Including external libraries + +Suppose you are using [Google Test](https://code.google.com/p/googletest/). You +can use one of the `new_` repository functions in the `WORKSPACE` file to +download Google Test and make it available in your repository: + +```python +new_http_archive( + name = "gtest", + url = "https://googletest.googlecode.com/files/gtest-1.7.0.zip", + sha256 = "247ca18dd83f53deb1328be17e4b1be31514cedfc1e3424f672bf11fd7e0d60d", + build_file = "gtest.BUILD", +) +``` + +Then create `gtest.BUILD`, a BUILD file to use to compile Google Test. +Google Test has several "special" requirements that make its `cc_library` rule +more complicated: + +* `gtest-1.7.0/src/gtest-all.cc` `#include`s all of the other files in + `gtest-1.7.0/src/`, so we need to exclude it from the compile or we'll get + link errors for duplicate symbols. +* It uses header files that relative to the `gtest-1.7.0/include/` directory + (`"gtest/gtest.h"`), so we must add that directory the include paths. +* It needs to link in pthread, so we add that as a `linkopt`. + +The final rule looks like this: + +```python +cc_library( + name = "main", + srcs = glob( + ["gtest-1.7.0/src/*.cc"], + exclude = ["gtest-1.7.0/src/gtest-all.cc"] + ), + hdrs = glob([ + "gtest-1.7.0/include/**/*.h", + "gtest-1.7.0/src/*.h" + ]), + copts = [ + "-Iexternal/gtest/gtest-1.7.0/include" + ], + linkopts = ["-pthread"], + visibility = ["//visibility:public"], +) +``` + +This is somewhat messy: everything is prefixed with gtest-1.7.0 as a byproduct +of the archive's structure. You can make `new_http_archive` strip this prefix by +adding the `strip_prefix` attribute: + +```python +new_http_archive( + name = "gtest", + url = "https://googletest.googlecode.com/files/gtest-1.7.0.zip", + sha256 = "247ca18dd83f53deb1328be17e4b1be31514cedfc1e3424f672bf11fd7e0d60d", + build_file = "gtest.BUILD", + strip_prefix = "gtest-1.7.0", +) +``` + +Then `gtest.BUILD` would look like this: + +```python +cc_library( + name = "main", + srcs = glob( + ["src/*.cc"], + exclude = ["src/gtest-all.cc"] + ), + hdrs = glob([ + "include/**/*.h", + "src/*.h" + ]), + copts = ["-Iexternal/gtest/include"], + linkopts = ["-pthread"], + visibility = ["//visibility:public"], +) +``` + +Now `cc_` rules can depend on `//external:gtest/main`. + +## Writing and running C++ tests + +For example, we could create a test `./test/hello-test.cc` such as: + +```cpp +#include "gtest/gtest.h" +#include "lib/hello-greet.h" + +TEST(FactorialTest, Negative) { + EXPECT_EQ(get_greet("Bazel"), "Hello Bazel"); +} +``` + +Then create `./test/BUILD` file for your tests: + +```python +cc_test( + name = "hello-test", + srcs = ["hello-test.cc"], + copts = ["-Iexternal/gtest/include"], + deps = [ + "@gtest//:main", + "//lib:hello-greet", + ], +) +``` + +Note in order to make `hello-greet` visible to `hello-test`, we have to add `"//test:__pkg__",` to `visibility` attribute in `./lib/BUILD`. + +Now you can use `bazel test` to run the test. + +{% highlight bash %} +$ bazel test test:hello-test +INFO: Found 1 test target... +Target //test:hello-test up-to-date: + bazel-bin/test/hello-test +INFO: Elapsed time: 4.497s, Critical Path: 2.53s +//test:hello-test PASSED in 0.3s + +Executed 1 out of 1 tests: 1 test passes. +{% endhighlight %} + + +## Adding dependencies on precompiled libraries + +If you want to use a library that you only have a compiled version of (e.g., +headers and a .so) wrap it in a `cc_library` rule: + +```python +cc_library( + name = "mylib", + srcs = ["mylib.so"], + hdrs = ["mylib.h"], +) +``` + +Then other C++ targets in your workspace can depend on this rule. diff --git a/site/docs/tutorial/environment.md b/site/docs/tutorial/environment.md index 8ce35d68a2..219060de7c 100644 --- a/site/docs/tutorial/environment.md +++ b/site/docs/tutorial/environment.md @@ -1,4 +1,91 @@ --- -layout: redirect -redirect: docs/tutorial/environment.html +layout: documentation +title: Tutorial - Set Up Your Environment --- + +# Tutorial - Set Up Your Environment + +The first step in this tutorial is to set up your environment. + +Here, you'll do the following: + +* Install Bazel +* Install Android Studio and the Android SDK +* Install Xcode (OS X only) +* Get the sample project from the GitHub repo + +## Install Bazel + +Follow the [installation instructions](/docs/install.md) to install Bazel and +its dependencies. + +## Install the Android SDK tools + +Do the following: + +1. Download and install the + [Android SDK Tools](https://developer.android.com/sdk/index.html#Other). + +2. Run the Android SDK Manager and install the following packages: + + <table class="table table-condensed table-striped"> + <thead> + <tr> + <td>Package</td> + <td>SDK directory</td> + </tr> + </thead> + <tbody> + <tr> + <td>Android SDK Platform Tools</td> + <td><code>platform-tools</code></td> + </tr> + <tr> + <td>Android SDK Build Tools</td> + <td><code>build-tools</code></td> + </tr> + <tr> + <td>Android SDK Platform</td> + <td><code>platform</code></td> + </tr> + </tbody> + </table> + + The SDK Manager is an executable named `android` located in the `tools` + directory. + +## Install Xcode (OS X only) + +If you are following the steps in this tutorial on Mac OS X, download and +install [Xcode](https://developer.apple.com/xcode/downloads/). The Xcode +download contains the iOS libraries, Objective-C compiler other tools +required by Bazel to build the iOS app. + +## Get the sample project + +You also need to get the sample project for the tutorial from GitHub: + +[https://github.com/bazelbuild/examples/](https://github.com/bazelbuild/examples/) + +The GitHub repo has two branches: `source-only` and `master`. The `source-only` +branch contains the source files for the project only. You'll use the files in +this branch in this tutorial. The `master` branch contains both the source files +and completed Bazel `WORKSPACE` and `BUILD` files. You can use the files in this +branch to check your work when you've completed the tutorial steps. + +Enter the following at the command line to get the files in the `source-only` +branch: + +```bash +$ cd $HOME +$ git clone -b source-only https://github.com/bazelbuild/examples +``` + +The `git clone` command creates a directory named `$HOME/examples/`. This +directory contains several sample projects for Bazel. The project files for this +tutorial are in `$HOME/examples/tutorial`. + +## What's next + +Now that you have set up your environment, you can +[set up a Bazel workspace](workspace.md). diff --git a/site/docs/tutorial/ios-app.md b/site/docs/tutorial/ios-app.md index e77b36907e..51774e9312 100644 --- a/site/docs/tutorial/ios-app.md +++ b/site/docs/tutorial/ios-app.md @@ -1,4 +1,206 @@ --- -layout: redirect -redirect: docs/tutorial/ios-app.html +layout: documentation +title: Tutorial - Build an iOS App --- + +# Tutorial - Build an iOS App + +Like the [Android app](android-app.md) you built in the previous step, the iOS +app is a simple mobile app that communicates with the +[backend server](backend-server.md). + +Here, you'll do the following: + +* Review the source files for the app +* Create a `BUILD` file +* Build the app for the simulator +* Find the build outputs +* Run/Debug the app on the simulator +* Build the app for a device +* Install the app on a device + +Note that, unlike with the Android app, you don't have to modify your +`WORKSPACE` file to add iOS-specific external dependencies. + +If you're following the steps in this tutorial on Mac OS X, you can go ahead +and build the sample iOS app as described below. If you are on Linux, skip ahead +to the [next step](backend-server.md). + +## Review the source files + +Let's take a look at the source files for the app. These are located in +`$WORKSPACE/ios-app/UrlGet`. Again, you're just looking at these files now to +become familiar with the structure of the app. You don't have to edit any of the +source files to complete this tutorial. + +## Create a BUILD file + +At a command-line prompt, open your new `BUILD` file for editing: + +```bash +$ vi $WORKSPACE/ios-app/BUILD +``` + +## Add an objc_library rule + +Bazel provides several build rules that you can use to build an app for the +iOS platform. For this tutorial, you'll first use the +[`objc_library`](/docs/be/objective-c.html#objc_library) rule to tell Bazel +how to build an +[static library](https://developer.apple.com/library/ios/technotes/iOSStaticLibraries/Introduction.html) +from the app source code and Xib files. Then you'll use the +`objc_binary` rule to tell it how to bundle the iOS application. (Note that +this is a minimal use case of the Objective-C rules in Bazel. For example, you +have to use the `ios_application` rule to build multi-architecture iOS +apps.) + +Add the following to your `BUILD` file: + +```python +objc_library( + name = "UrlGetClasses", + srcs = [ + "UrlGet/AppDelegate.m", + "UrlGet/UrlGetViewController.m", + ], + hdrs = glob(["UrlGet/*.h"]), + xibs = ["UrlGet/UrlGetViewController.xib"], +) +``` + +Note the name of the rule, `UrlGetClasses`. + +## Add an objc_binary rule + +The [`objc_binary`](/docs/be/objective-c.html#objc_binary) rule creates a +binary to be bundled in the application. + +Add the following to your `BUILD` file: + +```python +objc_binary( + name = "ios-app-binary", + srcs = [ + "UrlGet/main.m", + ], + deps = [ + ":UrlGetClasses", + ], +) + +``` +Note how the `deps` attribute references the output of the +`UrlGetClasses` rule you added to the `BUILD` file above. + +## Add an ios_application rule + +The [`ios_application`](/docs/be/objective-c.html#ios_application) rule +creates the bundled `.ipa` archive file for the application and also generates +an Xcode project file. + +Add the following to your `BUILD` file: + +```python +ios_application( + name = "ios-app", + binary = ":ios-app-binary", + infoplist = "UrlGet/UrlGet-Info.plist", +) +``` + +Now, save and close the file. You can compare your `BUILD` file to the +[completed example](https://github.com/bazelbuild/examples/blob/master/tutorial/ios-app/BUILD) +in the `master` branch of the GitHub repo. + +## Build the app for the simulator + +Make sure that your current working directory is inside your Bazel workspace: + +```bash +$ cd $WORKSPACE +``` + +Now, enter the following to build the sample app: + +```bash +$ bazel build //ios-app:ios-app +``` + +Bazel now launches and builds the sample app. During the build process, its +output will appear similar to the following: + +```bash +INFO: Found 1 target... +Target //ios-app:ios-app up-to-date: + bazel-bin/ios-app/ios-app.ipa + bazel-bin/ios-app/ios-app.xcodeproj/project.pbxproj +INFO: Elapsed time: 3.765s, Critical Path: 3.44s +``` + +## Find the build outputs + +The `.ipa` file and other outputs are located in the +`$WORKSPACE/bazel-bin/ios-app` directory. + +## Run/Debug the app on the simulator + +You can now run the app from Xcode using the iOS Simulator. To run the app, +open the project directory `$WORKSPACE/bazel-bin/ios-app/ios-app.xcodeproj` in +Xcode, choose an iOS Simulator as the runtime scheme and then click the **Run** +button. + +**Note:** If you change anything about the project file set in Xcode (for +example, if you add or remove a file, or add or change a dependency), you must +rebuild the app using Bazel and then re-open the project. + +## Build the app for a device + +You need to set up bazel so that it can find the appropriate provisioning +profile for the device you want to build for. To set up the "default" +provisioning profile for all bazel builds: + + 1. Go to [Apple Profiles](https://developer.apple.com/account/ios/profile/profileList.action) + and download the appropriate provisioning profile for your device. + If this is confusing, please refer to [Apple's documentation](https://developer.apple.com/library/ios/documentation/IDEs/Conceptual/AppDistributionGuide/MaintainingProfiles/MaintainingProfiles.html). + 1. Move your profile into `$WORKSPACE/tools/objc`. + 1. Optional - You may want to add your profile to your `.gitignore`. + 1. Edit `$WORKSPACE/tools/objc/BUILD` and add: + + ```python + filegroup( + name = "default_provisioning_profile", + srcs = ["<NAME OF YOUR PROFILE>.mobileprovision"], + ) + ``` + +Now you should be able to build the app for your device: + +```bash +$ bazel build //ios-app:ios-app --ios_multi_cpus=armv7,arm64 +``` + +This will build the app "fat". If you would prefer just to build for +your specific device architecture you can designate a single architecture. + +If you would like to select a specific Xcode version/SDK version you can do so +with the `--xcode_version=7.2 --ios_sdk_version=9.2` options. Make sure that +the Xcode version that you select has the appropriate SDK installed in it. + +If you would like to specify a minimum version of iOS to run against, you can +do so with the `--ios_minimum_os=7.0` option. + +## Install the app on a device + +The easiest way to install the app on the device is to launch Xcode and use the +`Windows > Devices` command. Select your plugged in device from the list on the +left, and then add the app by clicking on the "plus" sign under installed apps +and selecting the `.ipa` that you built. + +If your app does not launch, please make sure that your device was on your +provisioning profile. The `View Device Logs` button on the `Devices` screen in +Xcode may provide other information as to what has gone wrong. + +## What's next + +The next step is to build a [backend server](backend-server.md) for the two +mobile apps you built in this tutorial. diff --git a/site/docs/tutorial/java.md b/site/docs/tutorial/java.md index aeeac5483a..ce916667e1 100644 --- a/site/docs/tutorial/java.md +++ b/site/docs/tutorial/java.md @@ -1,4 +1,245 @@ --- -layout: redirect -redirect: docs/tutorial/java.html +layout: documentation +title: Build Java --- + +Build Java +========== + +You can use Bazel to build your Java application. In this tutorial you'll learn how to: + +* Build your first Java target +* Add dependencies to your target +* Use multiple packages +* Deploy your target + +## Setting up your workspace + +Suppose that you have an existing project in a directory, say, +`~/gitroot/my-project/`. Create an empty file at +`~/gitroot/my-project/WORKSPACE` to show Bazel where your project's root is. + +## Creating Your Own Build File + +Use the following commands to make a small Java project for this example: + +{% highlight bash %} +$ # If you're not already there, move to your workspace directory. +$ cd ~/gitroot/my-project +$ mkdir -p src/main/java/com/example +$ cat > src/main/java/com/example/ProjectRunner.java <<'EOF' +package com.example; + +public class ProjectRunner { + public static void main(String args[]) { + Greeting.sayHi(); + } +} +EOF +$ cat > src/main/java/com/example/Greeting.java <<'EOF' +package com.example; + +public class Greeting { + public static void sayHi() { + System.out.println("Hi!"); + } +} +EOF +{% endhighlight %} + +Bazel figures out what to build by looking for files named `BUILD` in your +workspace, so we'll create a `BUILD` file in the `~/gitroot/my-project` +directory. Add the following lines to this BUILD file: + +{% highlight python %} +# ~/gitroot/my-project/BUILD +java_binary( + name = "my-runner", + srcs = glob(["**/*.java"]), + main_class = "com.example.ProjectRunner", +) +{% endhighlight %} + +`java_binary` is the type of thing this rule will build. +`glob(["**/*.java"])` is a handy shorthand for "recursively include every file +that ends with .java" (see the +[build encyclopedia](be/functions.html#glob) for more information about +globbing). `com.example.ProjectRunner` specifies the class that contains the +main method. + +Now you are ready to build your Java binary: + +{% highlight bash %} +$ cd ~/gitroot/my-project +$ bazel build //:my-runner +INFO: Found 1 target... +Target //:my-runner up-to-date: + bazel-bin/my-runner.jar + bazel-bin/my-runner +INFO: Elapsed time: 1.021s, Critical Path: 0.83s +$ bazel-bin/my-runner +Hi! +{% endhighlight %} + +Congratulations, you've just built your first Bazel target! + +## Adding Dependencies + +Creating one rule to build your entire project may be sufficient for small +projects, but as projects get larger it's important to break up the build into +self-contained libraries that can be assembled into a final product. This way +the entire world doesn't need to be rebuilt on small changes and Bazel can +parallelize more of the build steps. + +To break up a project, create separate rules for each subcomponent and then +make them depend on each other. For the example above, add the following rules +to the `BUILD` file: + +{% highlight python %} +java_binary( + name = "my-other-runner", + srcs = ["src/main/java/com/example/ProjectRunner.java"], + main_class = "com.example.ProjectRunner", + deps = [":greeter"], +) + +java_library( + name = "greeter", + srcs = ["src/main/java/com/example/Greeting.java"], +) +{% endhighlight %} + +This builds the same files as before, but in a different way: now Bazel will +build the `greeter` library first and then build `my-other-runner`. Try building +and running `//:my-other-runner`: + +{% highlight bash %} +$ bazel run //:my-other-runner +INFO: Found 1 target... +Target //:my-other-runner up-to-date: + bazel-bin/my-other-runner.jar + bazel-bin/my-other-runner +INFO: Elapsed time: 2.454s, Critical Path: 1.58s + +INFO: Running command line: bazel-bin/my-other-runner +Hi! +{% endhighlight %} + +Now if you edit `ProjectRunner.java` and rebuild `my-other-runner`, +`Greeting.java` will not need to be recompiled. + +## Using Multiple Packages + +For larger projects, you will often be dealing with several directories. You +can refer to targets defined in other BUILD files using the syntax +`//path/to/directory:target-name`. For example, suppose +`src/main/java/com/example/` has a `cmdline/` subdirectory with the following +file: + +{% highlight bash %} +$ mkdir -p src/main/java/com/example/cmdline +$ cat > src/main/java/com/example/cmdline/Runner.java <<'EOF' +package com.example.cmdline; + +import com.example.Greeting; + +public class Runner { + public static void main(String args[]) { + Greeting.sayHi(); + } +} +EOF +{% endhighlight %} + +`Runner.java` depends on `com.example.Greeting`, so we could add a `BUILD` file +at `src/main/java/com/example/cmdline/BUILD` that contained the following rule: + +{% highlight python %} +# ~/gitroot/my-project/src/main/java/com/example/cmdline/BUILD +java_binary( + name = "runner", + srcs = ["Runner.java"], + main_class = "com.example.cmdline.Runner", + deps = ["//:greeter"] +) +{% endhighlight %} + +However, by default, build rules are _private_. This means that they can only be +referred to by rules in the same BUILD file. This prevents libraries that are +implementation details from leaking into public APIs, but it also means that you +must explicitly allow `runner` to depend on `//:greeter`. As is, if we +build `runner` we'll get a permissions error: + +{% highlight bash %} +$ bazel build //src/main/java/com/example/cmdline:runner +ERROR: /home/user/gitroot/my-project/src/main/java/com/example/cmdline/BUILD:2:1: + Target '//:greeter' is not visible from target '//src/main/java/com/example/cmdline:runner'. + Check the visibility declaration of the former target if you think the dependency is legitimate. +ERROR: Analysis of target '//src/main/java/com/example/cmdline:runner' failed; build aborted. +INFO: Elapsed time: 0.091s +{% endhighlight %} + +You can make a rule visible to rules in other BUILD files by adding a +`visibility = level` attribute. Change the `greeter` rule in +`~/gitroot/my-project/BUILD` to be visible to our new rule: + +{% highlight python %} +java_library( + name = "greeter", + srcs = ["src/main/java/com/example/Greeting.java"], + visibility = ["//src/main/java/com/example/cmdline:__pkg__"], +) +{% endhighlight %} + +This makes `//:greeter` visible to any rule in the +`//src/main/java/com/example/cmdline` package. Now we can build and +run the `runner` binary: + +{% highlight bash %} +$ bazel run //src/main/java/com/example/cmdline:runner +INFO: Found 1 target... +Target //src/main/java/com/example/cmdline:runner up-to-date: + bazel-bin/src/main/java/com/example/cmdline/runner.jar + bazel-bin/src/main/java/com/example/cmdline/runner +INFO: Elapsed time: 1.576s, Critical Path: 0.81s + +INFO: Running command line: bazel-bin/src/main/java/com/example/cmdline/runner +Hi! +{% endhighlight %} + +See the [build encyclopedia](be/common-definitions.html#common.visibility) for more +visibility options. + +## Deploying + +If you look at the contents of +_bazel-bin/src/main/java/com/example/cmdline/runner.jar_, you can see that it +only contains `Runner.class`, not its dependencies (`Greeting.class`): + +{% highlight bash %} +$ jar tf bazel-bin/src/main/java/com/example/cmdline/runner.jar +META-INF/ +META-INF/MANIFEST.MF +com/ +com/example/ +com/example/cmdline/ +com/example/cmdline/Runner.class +{% endhighlight %} + +This works for running locally (the `runner` script Bazel generates adds the +greeter jar to the classpath) but will not work if we want to copy `runner.jar` +to another machine and use it as a standalone binary. To build a self-contained +jar that can be deployed, build `runner_deploy.jar` (or, more generally, +`<target-name>_deploy.jar`): + +{% highlight bash %} +$ bazel build //src/main/java/com/example/cmdline:runner_deploy.jar +INFO: Found 1 target... +Target //src/main/java/com/example/cmdline:runner_deploy.jar up-to-date: + bazel-bin/src/main/java/com/example/cmdline/runner_deploy.jar +INFO: Elapsed time: 1.700s, Critical Path: 0.23s +{% endhighlight %} + +`runner_deploy.jar` will contain all of its dependencies. + + diff --git a/site/docs/tutorial/review.md b/site/docs/tutorial/review.md index 16557f7527..62d4501ad4 100644 --- a/site/docs/tutorial/review.md +++ b/site/docs/tutorial/review.md @@ -1,4 +1,29 @@ --- -layout: redirect -redirect: docs/tutorial/review.html +layout: documentation +title: Tutorial - Review --- + +# Tutorial - Review + +In this tutorial, you used Bazel to build an [Android app](android-app.md), +an [iOS app](ios-app.md) and a [backend server](backend-server.md) that runs on +Google App Engine. + +To build these software outputs, you: + +* Set up a Bazel [workspace](workspace.md) that contained the source code + for the components and a `WORKSPACE` that identifies the top level of the + workspace directory +* Created a `BUILD` file for each component +* Updated the `WORKSPACE` file to contain references to the required + external dependencies +* Ran Bazel to build the software components + +The built mobile apps and backend server application files are located in the +`$WORKSPACE/bazel-bin` directory. + +Note that completed `WORKSPACE` and `BUILD` files for this tutorial are located +in the +[master branch](https://github.com/bazelbuild/examples/tree/master/tutorial) +of the GitHub repo. You can compare your work to the completed files for +additional help or troubleshooting. diff --git a/site/docs/tutorial/workspace.md b/site/docs/tutorial/workspace.md index 76a2a7cd14..ff3f6da510 100644 --- a/site/docs/tutorial/workspace.md +++ b/site/docs/tutorial/workspace.md @@ -1,4 +1,53 @@ --- -layout: redirect -redirect: docs/tutorial/workspace.html +layout: documentation +title: Tutorial - Set Up a Workspace --- + +# Tutorial - Set Up a Workspace + +A [workspace](/docs/build-ref.html#workspaces) is a directory that contains the +source files for one or more software projects, as well as a `WORKSPACE` file +and `BUILD` files that contain the instructions that Bazel uses to build +the software. It also contains symbolic links to output directories in the +Bazel home directory. + +A workspace directory can be located anywhere on your filesystem. In this +tutorial, your workspace directory is `$HOME/examples/tutorial/`, which +contains the sample project files you cloned from the GitHub repo in the +previous step. + +Note that Bazel itself doesn't make any requirements about how you organize +source files in your workspace. The sample source files in this tutorial are +organized according to common conventions for Android apps, iOS apps and App +Engine applications. + +For your convenience, set the `$WORKSPACE` environment variable now to refer to +your workspace directory. At the command line, enter: + +```bash +$ export WORKSPACE=$HOME/examples/tutorial +``` + +## Create a WORKSPACE file + +Every workspace must have a text file named `WORKSPACE` located in the top-level +workspace directory. This file may be empty or it may contain references +to [external dependencies](/docs/external.html) required to build the +software. + +For now, you'll create an empty `WORKSPACE` file, which simply serves to +identify the workspace directory. In later steps, you'll update the file to add +external dependency information. + +Enter the following at the command line: + +```bash +$ touch $WORKSPACE/WORKSPACE +``` + +This creates the empty `WORKSPACE` file. + +## What's next + +Now that you've set up your workspace, you can +[build the Android app](android-app.md). |