这是关于Bazel的第二篇blog,前一篇写了安装、配置相关的东西,这一篇则是4个逐步推进的例子,改编自官方demo;以及相应的概念、文档链接等。

前提

  • Linux(Ubuntu, etc)或Mac OSX系统,会点儿命令行(包括brew/apt)
  • 装好了zsh和oh-my-zsh(用于bazel build等命令的补全)
  • 装好了bazel;
  • 学过C/C++;
  • 用过make/cmake
  • 最好会一点git
  • bazel版本:目前我用0.21版本,最新版删过东西(https://docs.bazel.build/versions/0.21.0/be/workspace.html)

基本概念

速查链接汇总

workspace规则

starlark预设全局变量

完整代码

stage1: 一个package, 一个target

这是最简单的bazel构建例子

目录结构

├── WORKSPACE
└── main
├── BUILD
└── hello.c

其中,main为包名,因为它包含了BUILD文件

hello.c:

#include <stdio.h>

int main(void){
printf("hello from C!\n");
return 0;
}

BUILD:

cc_binary(
name = "hello",
srcs = ["hello.c"],
)

执行构建

bazel build main:all
  • 语法是bazel build 包名:任务名
  • 输入完bazel build后按tab键补全提示,比较方便
  • 因为目前只有一个target,也可以输入bazel build main:hello

运行

bazel run main:all

它其实除了输出bazel相关的信息,执行的是./bazel-bin/hello目录下的可执行文件hello

执行清除

bazel clean

stage2: 一个package,多个target

典型场景:写一个库,然后调用它。这里写一个神经网络激活函数库,然后写一个测试程序。

目录结构

├── WORKSPACE
└── main
├── BUILD
├── activations.c
├── activations.h
└── testbed.c 1 directory, 5 files

BUILD:

cc_library(
name = "actv",
srcs = ["activations.c"],
hdrs = ["activations.h"],
) cc_binary(
name = "actv-testbed",
srcs = ["testbed.c"],
deps = [
":actv",
],
)

activations.h:

#ifndef __ACTIVATIONS_H__
#define __ACTIVATIONS_H__ float relu(float x);
float sigmoid(float x); #endif

activations.c:

#include "activations.h"
#include <math.h> float relu(float x){
if (x>=0) return x;
return 0;
} float sigmoid(float x){
return 1.0f / (1.0f + exp(-x));
}

testbed.c:

#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include "activations.h" // return a random float in (s, t)
float get_random(float s, float t){
float v = (float)(rand()) / RAND_MAX;
v = v * (t-s) + s;
return v;
} int main(){
const int maxn = 5;
srand(time(0));
for(int i=0; i<maxn; i++) {
float x = get_random(-2.0f, 2.0f);
float res_relu = relu(x);
float res_sigmoid = sigmoid(x);
printf("x=%f\n", x);
printf("relu(x)=%f\n", res_relu);
printf("sigmoid(x)=%f\n", res_sigmoid);
printf("\n");
} return 0;
}

构建库

bazel build main:actv

构建测试

bazel build main:actv-testbed

执行

bazel run main:actv-testbed

stage3: 多package,多target

主要是弄清楚,如何在不同package的target之间设定依赖关系,比如一个库target在其他包中是否可用(visibility),比如头文件的包含路径。

目录结构:

├── lib
│   ├── BUILD
│   ├── random.c
│   ├── random.h
│   ├── timer.c
│   └── timer.h
├── main
│   ├── activations.c
│   ├── activations.h
│   ├── BUILD
│   └── testbed.c
└── WORKSPACE

其中,lib/BUILD:

cc_library(
name = "timer",
srcs = ["timer.c"],
hdrs = ["timer.h"],
visibility = ["//main:__pkg__"]
) cc_library(
name = "random",
srcs = ["random.c"],
hdrs = ["random.h"],
visibility = ["//main:__pkg__"]
)

main/BUILD:

cc_library(
name = "actv",
srcs = ["activations.c"],
hdrs = ["activations.h"],
) cc_binary(
name = "actv-testbed",
srcs = ["testbed.c"],
deps = [
":actv",
"//lib:random",
"//lib:timer"
],
)

各个源码文件其实都很简单,这里就不贴出来的,只需要注意在包含lib包里面的头文件时,main/testbed.c是这样写的:

#include "activations.h"
#include "lib/timer.h"
#include "lib/random.h"

stage4: 使用外部依赖

这里说的外部依赖,包括:本地的其他目录,git仓库或http地址下载的。外部依赖可以是基于bazel构建的,也可以不是。

anyway,google家开源的abseil框架的hello-world例子可能是最典型的demo了。但是它同时用了gtest、gmock和abseil,感觉太麻烦了,干脆直接引入abseil外部库来写hello-world,如下:

目录结构

├── BUILD
├── hello.cc
└── WORKSPACE

这里看到并没有子目录,这也是可以的

WORKSPACE

# 非必须
workspace(name = "com_google_absl_hello_world") load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") # Abseil
http_archive(
name = "absl",
strip_prefix = "abseil-cpp-master",
urls = ["https://github.com/abseil/abseil-cpp/archive/master.zip"],
)

BUILD

cc_binary(
name = "hello",
srcs = ["hello.cc"],
deps = [
"@absl//absl/strings"
]
)

说明:因为在WORKSPACE中载入了absl,所以BUILD中可以使用@absl

hello.cc

#include <iostream>
#include <string> #include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h" using std::string;
using std::cout;
using std::endl; string Greet(absl::string_view person) {
return absl::StrCat("Hello ", person);
} int main(){
cout << Greet("world") << endl;
cout << Greet("ChrisZZ") << endl; return 0;
}

执行构建

bazel build :hello

它根据WORKSPACE中的设定(也就是http_archive),从http下载。其他的方法还包括git_repository的方式,不过最新版bazel中把这些都踢掉了,必须手动load一下bazel工具中的.bzl文件,才能用它们。。

参考:

https://stackoverflow.com/questions/45814669/c-project-with-bazel-and-gtest?noredirect=1&lq=1

https://github.com/vincent-picaud/Bazel_with_GTest

https://docs.bazel.build/versions/master/external.html

最佳实践

https://docs.bazel.build/versions/master/external.html#best-practices

使用Bazel构建C/C++项目的更多相关文章

  1. 为什么google bazel构建工具流行不起来

    作者Jack47 转载请保留作者和原文出处 之前博主写了系列文章Google软件构建工具Bazel原理及使用方法介绍.最近使用了一段时间后,觉得这个东西不是一种通用的构建工具,很难对接到情况复杂的大的 ...

  2. 使用maven一步一步构建spring mvc项目

    1      使用eclipse构建maven web项目 1.1新建Maven的web项目 打开菜单File –New-MavenProject. 点击Next 选择模板类型archtype——ma ...

  3. 使用Maven构建多模块项目

    [转] 使用Maven构建多模块项目 在平时的Javaweb项目开发中为了便于后期的维护,我们一般会进行分层开发,最常见的就是分为domain(域模型层).dao(数据库访问层).service(业务 ...

  4. Eclipse的maven构建一个web项目,以构建SpringMVC项目为例

    http://www.cnblogs.com/javaTest/archive/2012/04/28/2589574.html springmvc demo实例教程源代码下载:http://zuida ...

  5. 加速 Gradle 构建大型 Android 项目的方法[转]

    加速 Gradle 构建大型 Android 项目的方法 时间 2016-03-14 20:38:00  Mystra 原文  http://www.wangchenlong.org/2016/03/ ...

  6. Eclipse Maven构建Spring MVC项目

    工作中项目开发使用Maven管理项目的构建.打包.编译,框架採用的是Spring MVC框架,而且实现了多模块.多项目的管理.自己也简单的參与了架构的设计.对于刚開始学习的人来说,使用Maven构建项 ...

  7. 实现自动构建编译javaweb项目并发布到N台服务器

    前言 当你使用nginx实现了负载均衡,当你有了超过3台以上的应用服务器时,一个特别头疼的问题就来了,发布项目好麻烦. 你每次都要在本地编译打包一遍,然后手动复制到每一台服务器上面去,如果只有一两台服 ...

  8. 用Gradle构建Spring Boot项目

    相比起Maven的XML配置方式,Gradle提供了一套简明的DSL用于构建Java项目,使我们就像编写程序一样编写项目构建脚本.本文将从无到有创建一个用Gradle构建的Spring Boot项目, ...

  9. Ant + Jenkies +Tomcat 自动构建部署Web项目

    前言:博主资历尚浅,很多东西都还在刚起步学习的阶段,这几天开发任务比较轻,就在自己window系统下,模拟部署远程服务器,利用Jenkies + Ant + Tomcat 搭建了一个自动发布部署的环境 ...

随机推荐

  1. Oracle根据【日期】组,其他条件根据PIVOT行转列。使每个日期条件关联的其他数据只有一行。

    select OPER_TIME, MICROPAY, REFUND from ( select trunc(oper_time) oper_time, class_name, sum(total_f ...

  2. CF1098B/CF1099E Nice table

    题目地址:CF1098B/CF1099E Nice table 显然,a nice table需要满足如下条件: 要么,每行都由两个字符交替组成,相邻两行的字符均不相同 要么,每列都由两个字符交替组成 ...

  3. C++写文件

    头文件 ofstream -- 向文件写内容 实现代码 #include <vector> #include <string> #include <fstream> ...

  4. Linux的notifier机制在TP中的应用【转】

    转自:https://blog.csdn.net/armfpga123/article/details/51771666 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog ...

  5. MySQL中interactive_timeout和wait_timeout的区别【转】

    在用mysql客户端对数据库进行操作时,打开终端窗口,如果一段时间没有操作,再次操作时,常常会报如下错误: ERROR 2013 (HY000): Lost connection to MySQL s ...

  6. 题解-BOI 2004 Sequence

    Problem bzoj & Luogu 题目大意: 给定序列\(\{a_i\}\),求一个严格递增序列\(\{b_i\}\),使得\(\sum \bigl |a_i-b_i\bigr|\)最 ...

  7. selenium——获取元素的尺寸、文本信息、元素的属性、元素是否可见

    [is_disabled 可以用来检查元素是否存在]

  8. (并发编程)RLock(与死锁现象),Semaphore,Even事件,线程Queue

    一.死锁现象与递归锁所谓死锁: 是指两个或两个以上的进程或线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去.此时称系统处于死锁状态或系统产生了死锁,这些永远在 ...

  9. ubuntu中文版man

    man默认是英文的,但ubuntu的源里也有中文版的.以下是配置方法: 1)  终端输入sudo apt-get install manpages-zh 2)  安装后修改配置文件sudo gedit ...

  10. 19)django-cookie使用

    Cookie,有时也用其复数形式 Cookies,指某些网站为了辨别用户身份.进行 session 跟踪而储存在用户本地终端上的数据(通常经过加密) 一:cookie cookie在客户端浏览器的是以 ...