Bazel入门

来源:互联网 发布:淘宝查号131458查询 编辑:程序博客网 时间:2024/05/03 03:22

Bazel入门

上一篇博文中讲解了以Java工程bazel的使用,接下来讲解在C++工程中bazel的使用。

C++教程 
*建立工作区* 
假设目录中已经有了一个项目,对应 ~/gitroot/my-project/ 目录,先创建一个空的 ~/gitroot/my-project/WORKSPACE 工作区配置文件,用于表示这是Bazel项目对应的根目录。 在这里以下面目录结构创建一个小的hello world工程:

└── my-project    ├── lib    │   ├── BUILD    │   ├── hello-greet.cc    │   └── hello-greet.h    ├── main    │   ├── BUILD    │   ├── hello-time.cc    │   ├── hello-time.h    │   └── hello-world.cc    └── WORKSPACE
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

*创建源文件* 
使用下面的命令创建所需的源文件:

$ # 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();#endifEOF$ 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);#endifEOF$ 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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56

*添加BUILD文件* 
从上面的源代码可知,main/hello-world.cc要用到lib/hello-greet.h和main/hello-time.h。首先在lib目录下为hello-greet.cc创建BUILD:

cc_library(    name = "hello-greet",    srcs = ["hello-greet.cc"],    hdrs = ["hello-greet.h"],    visibility = ["//main:__pkg__"],)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

注意 visibility = [“//main:pkg“] 表示hello-greet对于main/BUILD是可见的。接下来在main目录下创建BUILD文件:

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",    ],)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

注意当依赖的包在同一目录下,只需用 :hello-time,当依赖的包在不同的目录下,需要用全路径://lib:hello-greet。 
现在可以建立hello world 的C++二进制程序了:

$ bazel build main:hello-worldINFO: Found 1 target...Target //main:hello-world up-to-date:  bazel-bin/main/hello-worldINFO: Elapsed time: 2.869s, Critical Path: 1.00s$ ./bazel-bin/main/hello-worldHello worldThu Jun 23 18:51:46 2016$ ./bazel-bin/main/hello-world BazelHello BazelThu Jun 23 18:52:10 2016
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

恭喜你刚刚成功构建了第一个Bazel项目了!

*传递依赖Transitive includes)* 
如果一个文件包含一个头文件,那么这个文件的规则也应该依赖与头文件的库,相反的,只有直接依赖需要被指定为依赖。例如,假设sandwich.h包括bread.h,而且bread.h包括flour.h,sandwich.h不包括flour.h,因此这个BUILD文件应该是这样:

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"],)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

在这里,sandwich库依赖于bread库,而bread库依赖于flour库。 
*添加包含路径(Adding include paths)* 
有时不能(或不愿)让依赖文件包含在工作区根目录的路径。现有的库可能已经拥有了包括与工作空间不匹配路径的目录。例如,假设有以下目录结构:

└── my-project    ├── third_party    │   └── some_lib    │       ├── BUILD    │       ├── include    │       │   └── some_lib.h    │       └── some_lib.cc    └── WORKSPACE
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

Bazel 希望 some_lib.h被包含在hird_party/some_lib/include/some_lib.h中,但假定some_lib.c要依赖于include/some_lib.h。为了使包含路径有效, third_party/some_lib/BUILD需要指定some_lib是一个包含目录:

cc_library(    name = "some_lib",    srcs = ["some_lib.cc"],    hdrs = ["some_lib.h"],    copts = ["-Ithird_party/some_lib"],)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

这对外部的依赖尤其有用,因为它们的头文件,否则必须被包含于外部/ [库名称]/前缀。

*包含外部库* 
假设正在用Google Test,可以在WORKSPACE文件中用一种新的库函数下载Google Test,使它在库中更适合:

new_http_archive(    name = "gtest",    url = "https://googletest.googlecode.com/files/gtest-1.7.0.zip",    sha256 = "247ca18dd83f53deb1328be17e4b1be31514cedfc1e3424f672bf11fd7e0d60d",    build_file = "gtest.BUILD",)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

然后创建gtest.BUILD,这个BUILD是用来编译Google Test的。Google Test有几个特殊的要求使它的cc_library规则更加复杂:

 - gtest-1.7.0/src/gtest-all.cc #includes 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.
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

最终的规则像这样:

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"],)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

这有点凌乱:一切都以前缀GTEST-1.7.0作为体系结构的副产品。可以通过添加strip_prefix属性使new_http_archive带这个前缀:

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",)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

此时的gtest.BUILD是这个样子:

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"],)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

现在cc_rules依赖于//external:gtest/main。

编写并运行C++测试程序 
例如,可以创建一个测试程序 ./test/hello-test.cc:

#include "gtest/gtest.h"#include "lib/hello-greet.h"TEST(FactorialTest, Negative) {  EXPECT_EQ(get_greet("Bazel"), "Hello Bazel");}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

然后为测试程序创建./test/BUILD文件:

cc_test(    name = "hello-test",    srcs = ["hello-test.cc"],    copts = ["-Iexternal/gtest/include"],    deps = [        "@gtest//:main",        "//lib:hello-greet",    ],)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

注意:为了使hello-greet对于hello-test可见,必须在./lib/BUILD添加”//test:pkg“可见属性。 
现在可以用bazel运行测试了。

$ bazel test test:hello-testINFO: Found 1 test target...Target //test:hello-test up-to-date:  bazel-bin/test/hello-testINFO: Elapsed time: 4.497s, Critical Path: 2.53s//test:hello-test                                                        PASSED in 0.3sExecuted 1 out of 1 tests: 1 test passes.
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

在预编译上添加依赖 
如果你想使用一个库,你只有(例如,头和一个.so)包装在一个cc_library规则的编译版本:

cc_library(    name = "mylib",    srcs = ["mylib.so"],    hdrs = ["mylib.h"],)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

然后在工作区中其他的C ++程序,可以依赖这条规则。

原创粉丝点击