aboutsummaryrefslogtreecommitdiffhomepage
path: root/site/docs/tutorial
diff options
context:
space:
mode:
authorGravatar Yun Peng <pcloudy@google.com>2016-06-24 18:01:03 +0000
committerGravatar Dmitry Lomov <dslomov@google.com>2016-06-27 11:39:16 +0000
commit1f63afaca0655b0948708ed38a129e4177633639 (patch)
tree711c068afeb232d4e727858e064b795feea35362 /site/docs/tutorial
parentdbc9c7c26023cbde329fb63d56f95db45b976bba (diff)
- Move Java-specific content to Java landing page
- Turn C++ Basic into a C++ language landing page - Reorganized tutorial menu -- MOS_MIGRATED_REVID=125796335
Diffstat (limited to 'site/docs/tutorial')
-rw-r--r--site/docs/tutorial/app.md (renamed from site/docs/tutorial/index.md)4
-rw-r--r--site/docs/tutorial/cpp.md360
-rw-r--r--site/docs/tutorial/java.md245
3 files changed, 607 insertions, 2 deletions
diff --git a/site/docs/tutorial/index.md b/site/docs/tutorial/app.md
index c7e5d24873..fdc33c5f83 100644
--- a/site/docs/tutorial/index.md
+++ b/site/docs/tutorial/app.md
@@ -1,9 +1,9 @@
---
layout: documentation
-title: Tutorial - Introduction
+title: Build Mobile Application
---
-# Tutorial - Introduction
+# 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
diff --git a/site/docs/tutorial/cpp.md b/site/docs/tutorial/cpp.md
new file mode 100644
index 0000000000..cea0a1c513
--- /dev/null
+++ b/site/docs/tutorial/cpp.md
@@ -0,0 +1,360 @@
+---
+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
+* Using external libraries
+* Writing and running C++ test
+* Using precompiled libraries
+
+## Setup 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 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"],
+)
+```
+
+This expresses that 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 libaries 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++ test
+
+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 then 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/java.md b/site/docs/tutorial/java.md
new file mode 100644
index 0000000000..1d2008b310
--- /dev/null
+++ b/site/docs/tutorial/java.md
@@ -0,0 +1,245 @@
+---
+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
+* Adding dependencies to your target
+* Using multiple packages
+* Deploying your target
+
+## Setup 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 visibile 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.
+
+