Skip to content
This repository has been archived by the owner on May 28, 2019. It is now read-only.

broc manual

doublesongsong edited this page Dec 28, 2015 · 10 revisions

#前言 broc基于源代码依赖完成软件的构建,而构建需要满足相关的前提条件才能顺利进行,本文描述了broc相关的构建规范,旨在引导用户快速了解并使用broc。 #目录规划 ##为什么规定目录的划分 ###确定依赖模块的版本 在SVN中同一个模块可能存在trunk, branch或tag三种情况。在broc编译时,如果主模块的同一个依赖模块存在多个版本时,就需要对其进行打平处理,即只保留其中一个版本。broc从模块的url中抽取出模块版本信息来完成依赖模块打平,因此依赖模块的url需要包含足够的信息:目录(模块)类型(trunk,branches或tags),模块的版本信息等。

###检出目录保持不变 模块在SVN中主干、分支和TAG的url各不相同,为了避免主模块在头文件包含时发生错误,broc要求checkout模块代码到本地时,要求检出目录保持一致。

##SVN URL 一个产品线通常情况下划分为多个功能模块,这一点体现到SVN的目录划分上表现为:一个产品线拥有一个代码根目录,在根目录下,每一个功能模块又对应一个子目录。 每个模块,在开发中会又分为不同的分支和tag,因此又会创建trunk,branches,tags三个目录加以区分,在这种情况下需要对模块的url做统一的规定,只有这样broc才能确定依赖模块的版本以及对应URL,进一步完成依赖模块的下载和编译。

SVN URL由四部分组成:域名/产品线目录/目录类型/模块名(分支名|tag名) 域名:SVN服务器域名地址,例如:https://github.com, 产品线目录:一个产品线对应一个产品代码的根目录,产品线根目录下包含了各模块的代码。例如:et/tools 目录类型:目录划分为trunk, branches和tags,分别对应模块的主干、分支和TAG 模块名|分支名|TAG名:分别指代在三种模块类型下模块的名称

该目录下包含trunk, branches, tags三个子目录,分别存储主干、分支和TAG的源代码

产品线et/tools的代码目录结构

https://github.comet/tools
                           ├── branches
                           │   ├── bar/bar_1-0-0-0_BRANCH
                           │   └── bar/bar_1-0-1-0_BRANCH
                           |   └── foo/foo_1-0-0-0_BRANCH
                           |   └── foo/foo_1-0-1-0_BRANCH
                           ├── tags
                           │   ├── bar/bar_1-0-0-0_PD_BL
                           │   └── foo/foo_1-0-0-0_PD_BL
                           │   └── foo/foo_1-0-0-1_PD_BL
                           └── trunk
                               ├── bar
                               └── foo

下面分trunk, branch和tag三种情况进行说明。 ###trunk url svn url = 域名/产品线目录/目录类型/模块名

例子:https://github.comet/tools/trunk/foo
域名 = https://github.com
产品名 = et/tools
目录类型 = trunk
模块名 = foo

###branch url svn url = 域名/产品线目录/目录类型/模块名/分支名 分支命名格式:"模块名_分支名_BRANCH", 分支名可以是任意字符串, "BRANCH"可通过[broc配置文件][broc配置文件]中配置项svn_postfix_branch进行更改

例子:https://github.com/et/tools/branches/foo/foo_1-0-0_BRANCH
域名 = https://github.com
产品线目录 = et/tools
目录类型 = branches
模块名 = foo
分支 = foo_1-0-0_BRANCH

###tag url SVN URL = 域名/产品线目录/目录类型/模块名/tag 名 tag命名格式:"模块名_版本号_PD_BL", "PD_BL"是PRODUCT_BASELINE的缩写,可以通过[broc配置文件][broc配置文件]中配置项svn_postfix_tag进行更改。 版本号的形式和位数不做限制,但是要求版本号能按照字典序进行大小比较。

例子:https://github.com/et/tools/tags/foo/foo_1-0-0-0_PD_BL
域名 = https://github.com
产品线目录 = et/tools
目录类型 = tags
模块名 = foo
tag名 = foo_1-0-0-0_PD_BL
版本号 = 1-0-0-0 

##GIT URL Git与SVN不同的地方在于,同一个模块的主干、分支和TAG的URL地址是一样的,这一点使得Git的路径划分就要比SVN简单得多。 假设:

产品线et/tools的git服务器域名https://github.com, 该产品线下包含了两个模块bar和foo。

###Repository broc推荐使用一个模块一个repository的模式, repository的命名形式为:"产品线名称/模块名称"。

###repo url 模块git url = 域名/repository名

示例:https://github.com/et/tools/foo
域名:https://github.com
repository:  et/tools/foo
示例:https://github.com/et/tools/foo
域名:https://github.com
repository:  et/tools/foo

###tag名 broc要求git下模块的tag要保持统一的命名方式,而且必须满足tag名能字典序进行大小判断,只有这样在依赖模块出现多个 TAG时,broc才能明确使哪个tag.

例如

'v1.0.0'和tag 'v1.0.1'
'v1.0.0' < 'v1.0.1'

需要避免如下命名方式不统一,造成的版本判断失败的情况

'v1.0.10' < 'v.1.0.9'

正确的做法

'v1.0.09' < 'v.1.0.10'

#相关术语、概念 ##模块、BROC文件 模块 模块被认为是一套实现了完整功能逻辑源代码集合。 在broc中,包含了BROC文件的目录被认为是一个模块,也是一个独立的构建单元。 BROC文件的作用域包含其目录下所有的文件和子目录, 子目录下不允许再包含BROC文件。

BROC文件 BROC文件必须放在模块的检出目录下,BROC文件作用的范围是其所在目录下的所有文件和子目录

~/workspace/my/app
.
├── BROC
└── src
   ├── foo1.cpp
   └── foo2.cpp

/workspace/my/app/BROC文件的作用域为:/workspace/my/app

主模块和依赖模块 模块从依赖关系的角度可以划分为主模块依赖模块

  • 主模块 指用户当前要构建的模块
  • 依赖模块 主模块的BROC文件中使用CONFIGS标签指定的模块

依赖模块从依赖的层级关系上可以划分为一级依赖模块二级依赖模块

  • 一级依赖模块 主模块的BROC文件中CONFIGS标签指定的依赖模块
  • 二级依赖模块 一级依赖模块自身的依赖模块,依次往下类推所有的依赖模块都算作二级依赖模块

##本地目录 ###工作空间 workspace目录是broc的工作目录,主模块和依赖模块的检出目录都是workspace目录的子目录,因此该目录是头文件和库文件的搜索路径的起始点。在BROC文件中使用宏变量$WORKSPACE来表示workspace目录。

###检出目录 即本地存放源代码的目录,代码检出目录必须是 workspace目录的直接子目录;同一模块的主干、分支和TAG的检出目录必须保持不变。

####SVN检出目录 代码检出目录要求忽略掉URL中的域名,trunk, tags, branches等关键字, 只保模块名。

#####trunk示例

模块:https://github.com/et/tools/trunk/foo
workspace: /home/broc/workspace,
代码检出目录为et/tools/foo
执行如下命令完成代码检出:cd /home/broc/workspace && svn checkout https://github.com/et/tools/trunk/foo et/tools/foo

#####branch示例

模块: https://github.com/et/tools/branches/foo_1-0-0_BRANCH
workspace : /home/broc/workspace
检出目录:et/tools/foo
检出命令:cd /home/broc/workspace && svn checkout https://github.com/et/tools/branches/foo_1-0-0_BRANCH et/tools/foo
说明:根据SVN URL的可以推断出代码检出目录,忽略域名https://github.com和关键字branches, 保留分支名中的模块名
https://github.com/et/tools/branches/foo_1-0-0_BRANCH  --->  et/tools/foo

#####tag示例

模块: https://github.com/et/tools/tags/foo_1-0-0-0_PD_BL
workspace : /home/broc/workspace
检出目录:et/tools/foo
检出命令:cd /home/broc/workspace && svn checkout https://github.com/et/tools/tags/foo_1-0-0_PD_BL et/tools/foo
说明:根据SVN URL的可以推断出代码检出目录, 忽略域名https://github.com和关键字tags, 保留tag名中的模块名foo
https://github.com/et/tools/branches/foo_1-0-0_BRANCH  --->  et/tools/foo

####git示例

模块:https://github.com/et/tools/foo
workspace: /home/broc/workspace
检出目录:et/tools/foo
检出命令:cd /home/broc/workspace && git clone https://github.com/et/tools/foo et/tools/foo

##产出目录 broc的编译结果都存放在$WORKSPACE/broc_out目录下,该目录称之为产出根目录,在BROC文件中使用变量$OUT_ROOT表示,一个$WORKSPACE对应一个$OUT_ROOT目录。

每个模块都有自己的产出目录,在BROC文件中使用变量$OUT表示。$OUT = $OUT_ROOT/代码的检出目录/output. $OUT根据结果文件的类型又划分为不同的子目录, 目录结构如下:

/home/broc/workspace
              |-- broc_out #产出根目录,BROC文件中使用$OUT_ROOT表示该目录
              |   |-- et
              |   |   |-- tools
              |   |   |   |-- foo       
              |   |   |   |   |-- output #模块产出目录,BROC文件中使用$OUT表示该目录
              |   |   |   |       |-- bin    # 执行文件目录
              |   |   |   |       |-- lib    # .a 文件目录
              |   |   |   |       |-- test   # 单测执行文件目录

SVN示例

foo svn url: https://github.com/et/tools/trunk/foo
bar svn url: https://github.com/et/tools/tags/bar_1-0-0-0_PD_BL
workspace: /home/broc/workspace
产出根目录$OUT_ROOT: /home/broc/workspace/broc_out
foo代码检出目录: /home/broc/workspace/et/tools/foo,
foo产出目录$OUT为: /home/broc/workspace/broc_out/et/tools/foo/output
bar代码检出目录: /home/broc/workspace/et/tools/bar,
bar产出目录$OUT为: /home/broc/workspace/broc_out/et/tools/bar/output

GIT示例

foo git url: https://github.com/et/tools/foo
bar git url: https://github.com/et/tools/bar
workspace : /home/broc/worksapce
产出根目录$OUT_ROOT: /home/broc/workspace/broc_out
foo代码检出目录: /home/broc/workspace/foo, 
foo产出目录$OUT为: /home/broc/workspace/broc_out/et/tools/foo/output
bar代码检出目录: /home/broc/workspace/et/tools/bar,
bar产出目录$OUT为: /home/broc/workspace/broc_out/et/tools/et/tools/bar/output

##头文件搜索路径 broc默认的头文件路径包含:

  • workspace目录 在BROC文件中使用$WORKSPACE表示
  • 产出根目录 在BROC文件中使用$OUT_ROOT表示
  • proto文件的产出目录 仅在标签PROTO_LIBRARY标签中默认添加该目录

建议在include头文件时,包含头文件的检出路径信息,这样不需要再额外指定头文件的搜索路径。 例如包含头文件util.h, 该文件检出路径为et/tools/bar/include/util.h, 建议这样包含:

#include "et/tools/bar/include/util.h"

在workspace下恰好能找到文件et/tools/bar/include/util.h

头文件搜索路径只包含workspace和产出根目录,这样头文件搜索路径数量少,搜索变得简单有效,而且能避免头文件同名导致包含错误的情况发生。 如果默认的头文件搜索路径不能满足要求,可以使用全局标签INCLUDE或include手动添加头文件搜索路径。

##默认不链接任何库文件

broc默认不链接BROC文件中指定的依赖模块,如果编译目标需要链接依赖库,需要使用标签Libs指定需要链接的库文件。这么做的原因和好处:

  1. 依赖模块生成的库文件并不一定是主模块都需要链接,主模块需要链接哪些库文件由主模块指定
  2. 能有效的减少链接的库文件,生成的可执行文件体积小
  3. 能有效避免库文件链接冲突
  4. 减少链接,加快编译速度

可以使用标签Libs添加依赖的库文件

Libs("/opt/protobuf/lib/libprotobuf.a","$OUT_ROOT/et/tools/app/output/lib/libPerson.a")
添加了依赖库文件libprotobuf.a和libPerson.a
其中$OUT_ROOT指代产出根目录,CONFIGS标签中指定的依赖库都需要使用"$OUT_ROOT 开头+模块库文件产出路径"的形式指定

##PROTO文件 在broc处理完proto文件后,其pb.cc和pb.h在对应的产出目录下, 举例如下:

可以看到proto的结果文件目录与proto文件目录是相互对应的,在workspace下,proto文件目录与结果文件目录只相差一个产出根目录broc_out

使用proto的头文件时,建议:

  • include头文件时,使用头文件的产出路径,例如#include "et/tools/bar/proto/test.pb.h"
  • 如果直接使用头文件名,即#include "test.pb.h"时,需要在头文件搜索路径中添加proto文件的检出目录
INCLUDE("et/tools/bar/proto")  #全局
Include("et/tools/bar/proto")  #局部

在PROTO_LIBRARY中使用Include添加的头文件搜索路径,同时也被用于protoc命令的--proto-path参数。

#依赖规范 broc不支持依赖模块在SVN和GIT同时管理的情况

##SVN依赖模块示例

###trunk依赖

CONFIGS("public/ub@trunk")                   # 依赖trunk最新代码
CONFIGS("public/ub@trunk@1000")              # 依赖trunk, revision为1000的代码

###branch依赖

CONFIGS("public/ub@ub_1-0-0-0_BRANCH")       # 依赖分支最新代码
CONFIGS("public/ub@ub_1-0-0-0_BRANCH@1000")  # 依赖branch, revision为1000的代码

###tag依赖

CONFIGS("public/ub@ub_1-0-0_PD_BL")          # 依赖 tag

#GIT模块依赖示例 ##分支依赖

CONFIGS("ub@master@branch")                  # 依赖master分支最新代码
CONFIGS("ub@dev@branch")                     # 依赖dev分支最新代码

##tag依赖

CONFIGS("ub@v1.0.0@tag")                     # 依赖tag v1.0.0的代码, "@tag"表示v1.0.0是tag名,不是分支名

#依赖规范

##依赖分类 一级依赖 主模块BROC文件指定的依赖模块 二级依赖 依赖模块自身的依赖模块,即依赖模块自身的BROC文件中指定依赖模块,依次类推,后续的依赖都认为是二级依赖

##依赖收集 一级依赖 来源于主模块的BROC文件 二级依赖 来源于一级依赖模块的BROC文件中包含的依赖模块,依次类推,更深层次的依赖一并作为二级依赖

##依赖打平

打平原则

  • 一级依赖和二级依赖存在版本冲突,以一级依赖的版本为准 例如:foo模块指定的一级依赖模块ub版本为1.0.0.0,而它又有二级依赖ub模块版本为1.0.1.0。此时以一级依赖的版本为准,即使用ub的1.0.0.0版本。
  • 二级依赖之间存在多个TAG,以较高的版本为准 例如:foo模块的二级依赖中同时有ub模块的1.0.0.0和1.0.1.0版本。此时以高版本为准,即使用ub的1.0.1.0版本。

###版本高低判断标准

  • SVN管理的模块 同一分支revision号大的为高版本 tag名中版本号大的为高版本
  • Git管理的模块 tag版本号大的为高版本

###依赖冲突 一般情况下,只有二级依赖才会出现依赖模块版本冲突的情况

SVN模块冲突

  • 同一依赖模块同时存在tag和branch CONFIGS("et/tools/ub@ub_1-0-0-0_PD_BL") CONFIGS("et/tools/ub@ub_1-0-0-0_BRANCH")

  • 同一依赖模块同时存在不同分支 CONFIGS("et/tools/ub@ub_1-0-0-0_BRANCH") CONFIGS("et/toos/ub@ub_1-0-0-1_BRANCH) CONFIGS("et/tools/ub@trunk")

####GIT模块冲突

  • 依赖模块同时存在不同分支 CONFIGS("et/tools/ps@master@branch") CONFIGS("et/tools/ps@dev@branch")

  • 依赖模块同在branch和tag CONFIGS("et/tools/ps@master@branch") CONFIGS("et/tools/ps@v1.0.0@tag")

#开发相关 TODO 代码上传后增加文档连接 ##流程图 流程图 ##时序图 时序图 ##缓存依赖关系图 依赖关系图 [broc配置文件]:https://github.com/baidu/broc/wiki/broc-tutorial#broc%E9%85%8D%E7%BD%AE [流程图]:*** [sequence_diagram]:https://github.com/baidu/broc/blob/master/doc/sequence_diagram.jpg [缓存依赖关系图]:***

Clone this wiki locally