blob: 8ae8595a112a21d21a87ccd48623427c62da437d [file] [log] [blame] [view]
Kristina Chodorowc1411502015-04-29 16:32:06 +00001---
2layout: documentation
David Chenc4af8282016-01-20 11:06:35 +00003title: C++ Basics
Kristina Chodorowc1411502015-04-29 16:32:06 +00004---
5
Googler3fb27ca2015-04-30 21:38:04 +00006C++ Basics
7==========
8
Kristina Chodorowc1411502015-04-29 16:32:06 +00009Use fully qualified include paths
Googler3fb27ca2015-04-30 21:38:04 +000010---------------------------------
Kristina Chodorowc1411502015-04-29 16:32:06 +000011
12Includes are relative to the root of your workspace. For example, suppose
13you have the following directory structure:
14
15```
16[workspace]/
17 WORKSPACE
18 a/
19 BUILD
20 a.h
21 a.cc
22 b/
23 BUILD
24 b.h
25 b.cc
26 main.cc
27```
28
David Chen62d200c2015-06-19 10:08:58 +000029If `b/main.cc` needs to include b.h then we'd create the following `b/BUILD`
Kristina Chodorowc1411502015-04-29 16:32:06 +000030file:
31
32```python
33cc_library(
34 name = "b",
35 srcs = ["b.cc"],
36 hdrs = ["b.h"],
37)
38
39cc_binary(
40 name = "main",
41 srcs = ["main.cc"],
42 deps = [":b"],
43)
44```
45
David Chen62d200c2015-06-19 10:08:58 +000046`b/main.cc` would have the following include statement:
Kristina Chodorowc1411502015-04-29 16:32:06 +000047
48```cpp
49#include "b/b.h"
50```
51
David Chen62d200c2015-06-19 10:08:58 +000052Note that the full path from the package root is used. If we want `b/main.cc` to
53also depend on `a/a.h`, we'd add the rule to `a/BUILD`:
Kristina Chodorowc1411502015-04-29 16:32:06 +000054
55```python
56cc_library(
57 name = "a",
58 srcs = ["a.cc"],
59 hdrs = ["a.h"],
60 visibility = ["//b:__pkg__"],
61)
62```
63
David Chen62d200c2015-06-19 10:08:58 +000064Then we'd add a dependency to `b/BUILD`:
Kristina Chodorowc1411502015-04-29 16:32:06 +000065
66```python
67cc_binary(
68 name = "main",
69 srcs = ["main.cc"],
70 deps = [
71 ":b",
72 "//a",
73 ],
74)
75```
76
David Chen62d200c2015-06-19 10:08:58 +000077And the following include to `b/main.cc`:
Kristina Chodorowc1411502015-04-29 16:32:06 +000078
79```cpp
80#include "a/a.h"
81```
82
David Chen62d200c2015-06-19 10:08:58 +000083`b/main.cc` will then be able to access symbols from `a/a.h` or `b/b.h`.
Kristina Chodorowc1411502015-04-29 16:32:06 +000084
85Transitive includes
Googler3fb27ca2015-04-30 21:38:04 +000086-------------------
Kristina Chodorowc1411502015-04-29 16:32:06 +000087
88If a file includes a header then the file's rule should depend on that header's
89library. Conversely, only direct dependencies need to be specified as
David Chen62d200c2015-06-19 10:08:58 +000090dependencies. For example, suppose `sandwich.h` includes `bread.h` and
91`bread.h` includes `flour.h`. `sandwich.h` doesn't include `flour.h` (who wants
Kristina Chodorowc1411502015-04-29 16:32:06 +000092flour in their sandwich?), so the BUILD file would look like:
93
94```python
95cc_library(
96 name = "sandwich",
97 srcs = ["sandwich.cc"],
98 hdrs = ["sandwich.h"],
99 deps = [":bread"],
100)
101
102cc_library(
103 name = "bread",
104 srcs = ["bread.cc"],
105 hdrs = ["bread.h"],
106 deps = [":flour"],
107)
108
109cc_library(
110 name = "flour",
111 srcs = ["flour.cc"],
112 hdrs = ["flour.h"],
113)
114```
115
David Chen3f16b562015-07-23 15:04:50 +0000116This expresses that the `sandwich` library depends on the `bread` library,
117which depends on the `flour` library.
Kristina Chodorowc1411502015-04-29 16:32:06 +0000118
119Adding include paths
Googler3fb27ca2015-04-30 21:38:04 +0000120--------------------
Kristina Chodorowc1411502015-04-29 16:32:06 +0000121
122Sometimes you cannot (or do not want to) base include paths at the workspace
123root. Existing libaries might already have a include directory that doesn't
124match its path in your workspace. For example, suppose you have the following
125directory structure:
126
127```
128[workspace]/
129 WORKSPACE
130 third_party/
131 some_lib/
132 include/
133 some_lib.h
134 BUILD
135 some_lib.cc
136```
137
David Chen62d200c2015-06-19 10:08:58 +0000138Bazel will expect `some_lib.h` to be included as
139`third_party/some_lib/include/some_lib.h`, but suppose `some_lib.cc` includes
Kristina Chodorowc1411502015-04-29 16:32:06 +0000140`"include/some_lib.h"`. To make that include path valid,
David Chen62d200c2015-06-19 10:08:58 +0000141`third_party/some_lib/BUILD` will need to specify that the `some_lib/`
Kristina Chodorowc1411502015-04-29 16:32:06 +0000142directory is an include directory:
143
144```python
145cc_library(
146 name = "some_lib",
147 srcs = ["some_lib.cc"],
148 hdrs = ["some_lib.h"],
Kristina Chodorowc97ee9c2015-10-08 14:58:34 +0000149 copts = ["-Ithird_party/some_lib"],
Kristina Chodorowc1411502015-04-29 16:32:06 +0000150)
151```
152
153This is especially useful for external dependencies, as their header files
David Chen62d200c2015-06-19 10:08:58 +0000154must otherwise be included with an `external/[repository-name]/` prefix.
Kristina Chodorowc1411502015-04-29 16:32:06 +0000155
156Including external libraries: an example
Googler3fb27ca2015-04-30 21:38:04 +0000157----------------------------------------
Kristina Chodorowc1411502015-04-29 16:32:06 +0000158
159Suppose you are using [Google Test](https://code.google.com/p/googletest/). You
David Chen62d200c2015-06-19 10:08:58 +0000160can use one of the `new_` repository functions in the `WORKSPACE` file to
Kristina Chodorow1b99f1b2015-05-08 13:34:43 +0000161download Google Test and make it available in your repository:
Kristina Chodorowc1411502015-04-29 16:32:06 +0000162
163```python
164new_http_archive(
Kristina Chodorow0f85e102015-05-22 14:03:02 +0000165 name = "gtest",
Kristina Chodorowc1411502015-04-29 16:32:06 +0000166 url = "https://googletest.googlecode.com/files/gtest-1.7.0.zip",
167 sha256 = "247ca18dd83f53deb1328be17e4b1be31514cedfc1e3424f672bf11fd7e0d60d",
168 build_file = "gtest.BUILD",
169)
Kristina Chodorowc1411502015-04-29 16:32:06 +0000170```
171
David Chen62d200c2015-06-19 10:08:58 +0000172Then create `gtest.BUILD`, a BUILD file to use to compile Google Test.
Kristina Chodorow1b99f1b2015-05-08 13:34:43 +0000173Google Test has several "special" requirements that make its `cc_library` rule
Kristina Chodorowc1411502015-04-29 16:32:06 +0000174more complicated:
175
David Chen62d200c2015-06-19 10:08:58 +0000176* `gtest-1.7.0/src/gtest-all.cc` `#include`s all of the other files in
177 `gtest-1.7.0/src/`, so we need to exclude it from the compile or we'll get
Kristina Chodorow4f806b52015-05-18 15:35:17 +0000178 link errors for duplicate symbols.
David Chen62d200c2015-06-19 10:08:58 +0000179* It uses header files that relative to the `gtest-1.7.0/include/` directory
Kristina Chodorowc97ee9c2015-10-08 14:58:34 +0000180 (`"gtest/gtest.h"`), so we must add that directory the include paths.
Kristina Chodorowc1411502015-04-29 16:32:06 +0000181* It needs to link in pthread, so we add that as a `linkopt`.
182
183The final rule looks like this:
184
185```python
186cc_library(
187 name = "main",
188 srcs = glob(
Kristina Chodorow4f806b52015-05-18 15:35:17 +0000189 ["gtest-1.7.0/src/*.cc"],
190 exclude = ["gtest-1.7.0/src/gtest-all.cc"]
Kristina Chodorowc1411502015-04-29 16:32:06 +0000191 ),
Kristina Chodorowc83c3002015-12-22 20:40:50 +0000192 hdrs = glob([
193 "gtest-1.7.0/include/**/*.h",
194 "gtest-1.7.0/src/*.h"
195 ]),
Kristina Chodorowc97ee9c2015-10-08 14:58:34 +0000196 copts = [
Kristina Chodorowc97ee9c2015-10-08 14:58:34 +0000197 "-Iexternal/gtest/gtest-1.7.0/include"
Kristina Chodorowc1411502015-04-29 16:32:06 +0000198 ],
199 linkopts = ["-pthread"],
200 visibility = ["//visibility:public"],
201)
202```
203
Kristina Chodorow443db5c2015-09-28 14:22:34 +0000204This is somewhat messy: everything is prefixed with gtest-1.7.0 as a byproduct
205of the archive's structure. You can make `new_http_archive` strip this prefix by
206adding the `strip_prefix` attribute:
207
208```python
209new_http_archive(
210 name = "gtest",
211 url = "https://googletest.googlecode.com/files/gtest-1.7.0.zip",
212 sha256 = "247ca18dd83f53deb1328be17e4b1be31514cedfc1e3424f672bf11fd7e0d60d",
213 build_file = "gtest.BUILD",
214 strip_prefix = "gtest-1.7.0",
215)
216```
217
218Then `gtest.BUILD` would look like this:
219
220```python
221cc_library(
222 name = "main",
223 srcs = glob(
224 ["src/*.cc"],
225 exclude = ["src/gtest-all.cc"]
226 ),
Kristina Chodorowc83c3002015-12-22 20:40:50 +0000227 hdrs = glob([
228 "include/**/*.h",
229 "src/*.h"
230 ]),
231 copts = ["-Iexternal/gtest/include"],
Kristina Chodorow443db5c2015-09-28 14:22:34 +0000232 linkopts = ["-pthread"],
233 visibility = ["//visibility:public"],
234)
235```
236
Kristina Chodorowc1411502015-04-29 16:32:06 +0000237Now `cc_` rules can depend on `//external:gtest/main`.
238
239For example, we could create a test such as:
240
241```cpp
242#include "gtest/gtest.h"
243
244TEST(FactorialTest, Negative) {
245 EXPECT_EQ(1, 1);
246}
247```
248
249Then create a BUILD file for your tests:
250
251```python
252cc_test(
253 name = "my_test",
254 srcs = ["my_test.cc"],
Emmanuel Jay3c222dc2016-01-14 09:19:58 +0000255 copts = ["-Iexternal/gtest/include"],
Kristina Chodorow0f85e102015-05-22 14:03:02 +0000256 deps = ["@gtest//:main"],
Kristina Chodorowc1411502015-04-29 16:32:06 +0000257)
258```
259
260You can then use `bazel test` to run the test.
Kristina Chodorow0efd26f2015-05-29 14:11:41 +0000261
262
263Adding dependencies on precompiled libraries
264--------------------------------------------
265
266If you want to use a library that you only have a compiled version of (e.g.,
267headers and a .so) wrap it in a `cc_library` rule:
268
269```python
270cc_library(
271 name = "mylib",
272 srcs = ["mylib.so"],
273 hdrs = ["mylib.h"],
274)
275```
276
277Then other C++ targets in your workspace can depend on this rule.