From c141150cb99c50baeb382b57755f14878073b91b Mon Sep 17 00:00:00 2001 From: Kristina Chodorow Date: Wed, 29 Apr 2015 16:32:06 +0000 Subject: [PATCH] Add some C++ documentation Fixes #32. -- MOS_MIGRATED_REVID=92358818 --- site/docs/cpp.md | 227 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 227 insertions(+) create mode 100644 site/docs/cpp.md diff --git a/site/docs/cpp.md b/site/docs/cpp.md new file mode 100644 index 00000000000000..01301044e2bc43 --- /dev/null +++ b/site/docs/cpp.md @@ -0,0 +1,227 @@ +--- +layout: documentation +--- + +Use fully qualified include paths +================================= + +Includes are relative to the root of your workspace. For example, suppose +you have the following directory structure: + +``` +[workspace]/ + WORKSPACE + a/ + BUILD + a.h + a.cc + b/ + BUILD + b.h + b.cc + main.cc +``` + +If _b/main.cc_ needs to include b.h then we'd create the following _b/BUILD_ +file: + +```python +cc_library( + name = "b", + srcs = ["b.cc"], + hdrs = ["b.h"], +) + +cc_binary( + name = "main", + srcs = ["main.cc"], + deps = [":b"], +) +``` + +_b/main.cc_ would have the following include statement: + +```cpp +#include "b/b.h" +``` + +Note that the full path from the package root is used. If we want _b/main.cc_ to +also depend on _a/a.h_, we'd add the rule to _a/BUILD_: + +```python +cc_library( + name = "a", + srcs = ["a.cc"], + hdrs = ["a.h"], + visibility = ["//b:__pkg__"], +) +``` + +Then we'd add a dependency to _b/BUILD_: + +```python +cc_binary( + name = "main", + srcs = ["main.cc"], + deps = [ + ":b", + "//a", + ], +) +``` + +And the following include to _b/main.cc_: + +```cpp +#include "a/a.h" +``` + +_b/main.cc_ will then be able to access symbols from _a/a.h_ or _b/b.h_. + +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: + +``` +[workspace]/ + WORKSPACE + third_party/ + some_lib/ + include/ + some_lib.h + BUILD + some_lib.cc +``` + +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"], + includes = ["."], +) +``` + +This is especially useful for external dependencies, as their header files +must otherwise be included with an "external/[repository-name]/" prefix. + +Including external libraries: an example +======================================== + +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 create +the repository: + +```python +new_http_archive( + name = "gtest-repo", + url = "https://googletest.googlecode.com/files/gtest-1.7.0.zip", + sha256 = "247ca18dd83f53deb1328be17e4b1be31514cedfc1e3424f672bf11fd7e0d60d", + build_file = "gtest.BUILD", +) + +bind( + name = "gtest/main", + actual = "@gtest-repo//:main", +) +``` + +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: + +* It has a .cc file that `#include`s all of the other files in _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 _include/_ directory + (`"gtest/gtest.h"`), so we must add that directory the includes. +* It uses "private" header files in src/, so we add "." to the includes so it + can `#include "src/gtest-internal-inl.h"`. +* 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( + ["src/*.cc"], + exclude=["src/gtest-all.cc"] + ), + hdrs = glob(["include/**/*.h"]), + includes = [ + ".", + "include" + ], + linkopts = ["-pthread"], + visibility = ["//visibility:public"], +) +``` + +Now `cc_` rules can depend on `//external:gtest/main`. + +For example, we could create a test such as: + +```cpp +#include "gtest/gtest.h" + +TEST(FactorialTest, Negative) { + EXPECT_EQ(1, 1); +} +``` + +Then create a BUILD file for your tests: + +```python +cc_test( + name = "my_test", + srcs = ["my_test.cc"], + deps = ["//external:gtest/main"], +) +``` + +You can then use `bazel test` to run the test.