bazel是谷歌提出的新编译工具,目的在于取代现存的make和cmake等老旧的编译工具。其具有相当优秀的编译速度,且使用方法易于上手,下面就来说说怎么使用bazel来编译C++代码。
项目
├── main(源代码所在文件夹)
│ ├── BUILD
│ └── print.cpp
└── WORKSPACE
==============================
WORKSPACE用不上的话,内容可以为空,只象征着工作空间的主目录所在
只有一个print.cpp文件,代码如下:
// Copyright [2021]
#include
#include
#include
void PrintLocaltime() {
std::time_t result = std::time(nullptr);
std::cout << std::asctime(std::localtime(&result));
}
int main() {
std::cout << "I was created by bazel" << std::endl;
PrintLocaltime();
return 0;
}
正常情况下我们使用g++ print.cpp -o print.o来编译代码,当使用bazel编译的时候BUILD文件应该这样写:
load("@rules_cc//cc:defs.bzl", "cc_binary")
cc_binary(
name = "print",
srcs = ["print.cpp"],
)
===============================
编译命令如下:
bazel build //main:print
其中//表示WORKSPACE所在的工作目录,main为工作目录下的main文件夹,print为main文件夹中被编译的对象文件(即cc_binary下面的name)
1.load语句的作用在于加载bazel的相关扩展包
2.第一个参数代表扩展包的位置,第二个参数表示扩展包中的规则、函数、常量(字符串、列表等)
3.上面的语句作用为:加载@rules_cc//cc:defs.bzl并添加其中定义的符号cc_binary到当前环境
4.规则的类型,一般以编程语言为前缀,例如cc,java,后缀通常有:
*_binary 用于构建目标语言的可执行文件
*_test 用于自动化测试,其目标是可执行文件,如果测试通过应该退出0
*_library 用于构建目标语言的库
// 文件夹的结构如下
├── main
│ ├── BUILD
│ ├── main.cpp
│ ├── print.cpp
│ └── print.h
└── WORKSPACE
// Copyright [year]
#include
#include
#include "main/print.h"
int main() {
std::string str = "I love you.";
PrintAny(str);
return 0;
}
// Copyright [year]
#pragma once
#include
#include
void One();
void PrintAny(const std::string& str);
// Copyright [year]
#include "main/print.h"
void One() {
std::cout << "one" << std::endl;
}
void PrintAny(const std::string& str) {
std::cout << str << std::endl;
}
load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library")
cc_library(
name = "print",
srcs = ["print.cpp"],
hdrs = ["print.h"],
)
cc_binary(
name = "main",
srcs = ["main.cpp"],
deps = [
"//main:print",
],
)
// load中加入的规则有:cc_binary和cc_library,cc_library用来编译头文件
// 在cc_binary中加入了deps,构建的可执行文件依赖于main文件夹下的print(即,cc_library中的name)
文件目录如下:
├── lib(main源文件依赖于此文件夹下的count.h)
│ ├── BUILD
│ ├── count.cpp
│ └── count.h
├── main
│ ├── BUILD
│ └── main.cpp
└── WORKSPACE
// 文件名:count.h
// Copyright [year]
#include
#include
int Add(const int& a, const int& b);
// 文件名:count.cpp
// Copyright [year]
#include "lib/count.h"
int Add(const int& a, const int& b) {
return a+b;
}
其中lib文件夹下的BUILD文件的写法如下:
load("@rules_cc//cc:defs.bzl", "cc_library")
cc_library(
name = "count",
srcs = ["count.cpp"],
hdrs = ["count.h"],
visibility = ["//main:__pkg__"],
)
// 要使count对main文件夹下的文件可见,需要在./lib/BUILD文件中添加属性visibility,值为//main:__pkg__
// Copyright [year]
#include
#include
#include "lib/count.h"
int main() {
int a = 1;
int b = 2;
int c = Add(a, b);
std::cout << c << std::endl;
return 0;
}
其中main文件夹中的BUILD文件写法如下:
load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library")
cc_binary(
name = "main",
srcs = ["main.cc"],
deps = [
"//lib:count",
],
)
注意:因为要依赖于lib文件夹中的count,所以要加入deps来表示可执行文件需要依赖于lib文件夹中的count。
工作目录如下:
.
├── main
│ ├── BUILD
│ ├── main.cpp
│ ├── ThreadPool.cpp
│ └── ThreadPool.h
└── WORKSPACE
因为用到了线程,所以需要编译选项 -lpthread,makefile的编写如下:
CFLAG = -std=c++11
LIB = -lpthread
OBJECTS = test ThreadPool.o
test: main.cpp ThreadPool.o
g++ main.cpp ThreadPool.o -o test $(CFLAG) $(LIB)
ThreadPool.o: ThreadPool.cpp
g++ -c ThreadPool.cpp $(CFLAG) $(LIB)
.PHONY:clean
clean:
rm $(OBJECTS)
load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library")
cc_library(
name = "ThreadPool",
srcs = ["TC_ThreadPool.cpp"],
hdrs = ["TC_ThreadPool.h"],
)
cc_binary(
name = "main",
srcs = ["main.cpp"],
deps = [
":ThreadPool",
],
linkopts = ["-lpthread", "-std=c++11"],
)
注意:因为编译时需要多线程以及C++11的支持,所以在编译target对应的cc_binary中加入了linkopts,只需要在其中放置编译选项即可。
关于bazel的基本使用方法就只简单介绍到这了,详细的使用方法可以查看官方的文档。