当前位置: 首页 > news >正文

白沟做网站个人品牌打造方案

白沟做网站,个人品牌打造方案,咨询公司,做免费推广的网站有哪些简介 Bazel Google开源的#xff0c;是一款与 Make、Maven 和 Gradle 类似的开源构建和测试工具。 它使用人类可读的高级构建语言。Bazel 支持多种语言的项目#xff0c;可为多个平台构建输出。Bazel支持任意大小的构建目标#xff0c;并支持跨多个代码库和大量用户的大型代…简介 Bazel Google开源的是一款与 Make、Maven 和 Gradle 类似的开源构建和测试工具。 它使用人类可读的高级构建语言。Bazel 支持多种语言的项目可为多个平台构建输出。Bazel支持任意大小的构建目标并支持跨多个代码库和大量用户的大型代码库。是Google主推的一种构建工具。 优劣势 优势 官方说明 高级构建语言。Bazel 使用人类可读的抽象语言在较高的语义级别描述项目的构建属性。与其他工具不同Bazel 的运作涉及库、二进制文件、脚本和数据集的概念可以避免将单个调用编写到编译器和链接器等工具的复杂性。 Bazel 既快速又可靠。Bazel 会缓存之前完成的所有工作并跟踪文件内容和 build 命令的更改。这样Bazel 就会知道何时需要重新构建应用并且只会重新构建。为了进一步加快构建速度您可以将项目设置为以高度并行的方式进行构建。 Bazel 是多平台的。Bazel 可在 Linux、macOS 和 Windows 上运行。Bazel 可以从同一项目为多个平台包括桌面设备、服务器和移动设备构建二进制文件和可部署软件包。 Bazel 支持扩缩。在处理包含 10 万个以上源文件的构建时Bazel 可保持敏捷性。它可以处理数以万计的多个代码库和用户群。 Bazel 可扩展。它支持许多语言您可以扩展 Bazel以支持任何其他语言或框架。 其它人总结 很方便地获取第三方依赖 构建多语言的软件系统One ToolAll Languages 优秀的缓存和依赖计算编译速度非常优异 DevOps部署云构建可极大复用宝贵的计算资源 快(Fast) Bazel的构建过程很快它集合了之前构建系统的加速的一些常见做法。包括 1.增量编译。只重新编译必须的部分即通过依赖分析只编译修改过的部分及其影响的路径。 2. 并行编译。将没有依赖的部分进行并行执行可以通过--jobs来指定并行流的个数一般可以是你机器CPU的个数。遇到大项目马力全开时Bazel能把你机器的CPU各个核都吃满。 3. 本地缓存远程缓存。Bazel将构建过程视为函数式的只要输入给定那么输出就是一定的。而不会随着构建环境的不同而改变当然这需要做一些限制这样就可以分布式的缓存/复用不同模块这点对于超大项目的速度提升极为明显。 4. 远程构建。默认情况下Bazel 会在本地机器上执行构建和测试。通过 Bazel 构建的远程执行您可以将构建和测试操作分散到多个机器例如数据中心。 可伸缩(scalable) Bazel号称无论什么量级的项目都可以应对无论是超大型单体项目monorepo、还是超多库的分布式项目multirepo。Bazel还可以很方便的集成CD/CI 并在云端利用分布式环境进行构建。 它使用沙箱机制进行编译即将所有编译依赖隔绝在一个沙箱中比如编译golang项目时不会依赖你本机的GOPATH从而做到同样源码、跨环境编译、输出相同即构建的确定性。 跨语言(multi-language) 如果一个项目不同模块使用不同的语言利用Bazel可以使用一致的风格来管理项目外部依赖和内部依赖。典型的项目如 Ray。该项目使用C构建Ray的核心调度组件、通过Python/Java来提供多语言的API并将上述所有模块用单个repo进行管理。如此组织使其项目整合相当困难但Bazel在此处理的游刃有余大家可以去该repo一探究竟。 可扩展(extensible) Bazel使用的语法是基于Python裁剪而成的一门语言Startlark。其表达能力强大往小了说可以使用户自定义一些rules类似一般语言中的函数对构建逻辑进行复用往大了说可以支持第三方编写适配新的语言或平台的rules集比如rules go。 Bazel并不原生支持构建golang工程但通过引入rules go 就能以比较一致的风格来管理golang工程。 劣势 隔离未遵循程惯例从策略上看Bazel从其他遗留库获取代码这是必须的否则Bazel自己完蛋了其他库要想从Bazel获取用户也必须使用Bazel用户真的被强绑定了。 依赖于JVM。 安装 采取“使用二进制安装程序”参考https://bazel.build/install/ubuntu?hlzh-cn#binary-installer 工程介绍 参考官方示例项目git clone https://github.com/bazelbuild/examples 具体结构如下 examples └── cpp-tutorial├──stage1│ ├── main│ │ ├── BUILD│ │ └── hello-world.cc│ └── WORKSPACE├──stage2│ ├── main│ │ ├── BUILD│ │ ├── hello-world.cc│ │ ├── hello-greet.cc│ │ └── hello-greet.h│ └── WORKSPACE└──stage3├── main│ ├── BUILD│ ├── hello-world.cc│ ├── hello-greet.cc│ └── hello-greet.h├── lib│ ├── BUILD│ ├── hello-time.cc│ └── hello-time.h└── WORKSPACE 使用Bazel管理的项目一般包含以下几种Bazel相关的文件WORKSPACE(同WORKSPACE.bazel)BUILD(同BUILD.bazel).bzl 和 .bazelrc 等。 如何工作 当运行构建或者测试时Bazel会 加载和目标相关的BUILD文件 分析输入及其依赖应用指定的构建规则产生一个Action图。这个图表示需要构建的目标、目标之间的关系以及为了构建目标需要执行的动作。Bazel依据此图来跟踪文件变动并确定哪些目标需要重新构建 针对输入执行构建动作直到最终的构建输出产生出来 WORKSPACE文件--项目工作区 WORKSPACE文件用于将目录及其内容识别为 Bazel 工作区它位于项目目录结构的根目录中。该文件可能为空或可能定义加载 Bazel 工具和 rules 集以及包含对构建输出所需的外部依赖项的引用。 BUILD文件--软件包 软件包指包含名为BUILD或BUILD.bazel的efhttps://bazel.build/concepts/build-files?hlzh-cnBUILD文件的目录。代码库中的主要代码组织单元是软件包。软件包是相关文件的集合以及如何使用这些文件生成输出工件的规范。软件包中包含其目录中的所有文件及其下的所有子目录但包含BUILD文件的文件除外。根据该定义任何文件或目录都不得是两个不同软件包的一部分。 BUILD 文件包含 Bazel 的几种不同类型的指令。每个 BUILD 文件都需要至少一条规则作为一组指令告诉 Bazel 如何构建所需的输出例如可执行文件或库。BUILD 文件中的 build 规则的每个实例都称为一个目标target并指向一组特定的源文件和依赖项。 目标还可以指向其他目标。 查看 stage3/lib/BUILD 文件 cc_library(name hello-time,srcs [hello-time.cc],hdrs [hello-time.h],visibility [//main:__pkg__], ) 在 stage3/main/BUILD 文件 cc_library(name hello-greet,srcs [hello-greet.cc],hdrs [hello-greet.h], )cc_binary(name hello-world,srcs [hello-world.cc],deps [:hello-greet,//lib:hello-time,], ) 在此示例中hello-world 目标会实例化 Bazel 的内置 cc_binary rule。该规则指示 Bazel 从hello-world.cc 源文件和两个依赖项hello-greet和//lib:hello-time构建独立的可执行文件。 为使构建成功您可以使用可见性属性让 lib/BUILD 中的 //lib:hello-time 目标明确显示给 main/BUILD 中的目标。这是因为默认情况下目标仅对同一 BUILD 文件中的其他目标可见。Bazel 使用目标可见性来防止出现包含有实现细节的库泄露到公共 API 等问题。 target定义--目标 软件包是目标软件包的容器在软件包的BUILD文件中定义。大多数目标是两种主要类型之一文件和规则。如示例中的hello-world和hello-greet等。 文件进一步分为两种。源文件通常由用户编写并签入代码库。生成的文件有时称为派生文件或输出文件不会被签入但是从源文件生成的。 第二种目标使用规则声明。每个规则实例都用于指定一组输入文件与一组输出文件之间的关系。规则的输入可以是源文件但也可以是其他规则的输出。 .bzl文件 如果你的项目有一些复杂构造逻辑、或者一些需要复用的构造逻辑那么可以将这些逻辑以函数形式保存在.bzl文件供WORKSPACE或者BUILD文件调用。其语法跟Python类似。 .bazelrc文件 对于Bazel来说如果某些构建动作都需要某个参数就可以将其写在此配置中从而省去每次敲命令都重复输入该参数。Bazel 会按以下顺序读取可选的 bazelrc 文件 系统级文件位于 etc/bazel.bazelrc。 位于 $workspace/tools/bazel.rc 的 Workspace rc 文件。 主目录文件位于 $HOME/.bazelrc 中 此处列出的每个 bazelrc 文件都有一个对应的标志可用于停用这些标志例如 --nosystem_rc、--noworkspace_rc 和 --nohome_rc。您还可以通过传递 --ignore_all_rc_files 启动选项让 Bazel 忽略所有 Bazelrcs。 构建 运行以下命令以切换到 stage3 目录 cd stage3 运行以下命令 bazel build //main:hello-world 在目标标签中//main:部分是BUILD文件相对于工作区根目录的位置hello-world是BUILD文件中的目标名称。 Bazel 会生成如下所示 INFO: Found 1 target... Target //main:hello-world up-to-date:bazel-bin/main/hello-world INFO: Elapsed time: 0.167s, Critical Path: 0.00s 运行以下命令可删除输出文件并可选择停止服务器。 bazel clean 运行 执行二进制文件以获得最终的 Hello world 消息 bazel-bin/main/hello-world 依赖图 生成依赖图 INFO: Found 1 target... Target //main:hello-world up-to-date:bazel-bin/main/hello-world INFO: Elapsed time: 0.167s, Critical Path: 0.00s 将生成的输出图文字描述, 粘贴到 GraphViz, 生成的依赖图如下 构建原理 调度模型 传统构建系统有很多是基于任务的例如 AntMavenGradle。用户可以自定义任务(Task例如执行一段 shell 脚本。用户配置它们的依赖关系构建系统则按照顺序调度。 ​ 基于 Task 的调度模型:这种模式对使用者很友好他可以专注任务的定义而不用关心复杂的调度逻辑。构建系统通常给予任务制定者极大的权利比如 Gradle 允许用户用 Java 代码编写任务原则上可以做任何事。 如果一个任务在输入条件不变的情况下永远输出相同的结果我们就认为这个任务是封闭(Hermeticity) 的。构建系统可以利用封闭性提升构建效率例如第二次构建时跳过某些输入没变的 Task这种方式也称为 增量构建。 不满足封闭性的任务则会导致增量构建失效例如 Task 访问某个互联网资源或者 Task 在执行时依赖随机数或时间戳这样的动态特征这些都会导致多次执行 Task 得到不同的结果。 Bazel 采用了不同的调度模型它是基于目标Target【制品 (Artifact) 的】。Bazel 官方定义了一些规则 (rule)用于构建某些特定产物例如 c 的 library 或者 go 语言的 package用户配置和调用这些规则。他仅仅需要告诉 Bazel 要构建什么 target而由 Bazel 来决定如何构建它。 规则由官方和可信赖第三方维护规则产生的任务满足封闭性需求这使得用户可以信赖系统的增量构建能力。 bazel基于 Target 的调度模型如下图所示 ​File 表示原始文件Target 表示构建时生成的文件。当用户告诉 Bazel 要构建某个 Target 的时候Bazel 会分析这个文件如何构建构建动作定义为 Action和其他构建系统的 Task 大同小异如果 Target 依赖了其他 TargetBazel 会进一步分析依赖的 Target 又是如何构建生成的这样一层层分析下去最终绘制出完整的执行计划。 并行编译 Bazel 精准的知道每个 Action 依赖哪些文件这使得没有相互依赖关系的 Action 可以并行执行而不用担心竞争问题。基于任务的构建系统则存在这样的问题 ​ 基于任务的构建系统存在竞争问题:两个 Task 都会向同一个文件写一行字符串这就造成两个 Task 的执行顺序会影响最终的结果。要想得到稳定的结果就需要定义这两个 Task 之间的依赖关系。 Bazel 的 Action 由构建系统本身设计更加安全也不会出现类似的竞争问题。因此我们可以充分利用多核 CPU 的特性让 Action 并行执行。 通常我们采用 CPU 逻辑核心数作为 Action 执行的并发度如果开启了远端执行 (后面会提到)则可以开启更高的并发度。 增量编译 对 Bazel 来说每个 Target 的构建过程都对应若干 Action 的执行。Action 的执行本质上就是输入文件 编译命令 环境信息 输出文件的过程。 ​Action 的描述: 如果本地文件系统保留着上一次构建的 outputs此时 Bazel 只需要分析 inputs, commands 和 envs 和上次相比有没有改变没有改变就直接跳过该 Action 的执行。 这对于本地开发非常有用如果你只修改了少量代码Bazel 会自动分析哪些 Action 的 inputs 发生了变化并只构建这些 Action整体的构建时间会非常快。 不过增量构建并不是 Bazel 独有的能力大部分的构建系统都具备。但对于几万个文件的大型工程如果不修改一行代码只有 Bazel 能在一秒以内构建完毕其他系统都至少需要几十秒的时间这简直就是 降维打击 了。 Bazel 是如何做到的呢 首先Bazel 采用了 Client/Server 架构当用户键入 bazel build 命令时调用的是 bazel 的 client 工具而 client 会拉起 server并通过 grpc 协议将请求 (buildRequest) 发送给它。由 server 负责配置的加载ActionGraph 的生成和执行。 构建结束后Server 并不会立即销毁而 ActionGraph 也会一直保存在内存中。当用户第二次发起构建时Bazel 会检测工作空间的哪些文件发生了改变并更新 ActionGraph。如果没有文件改变就会直接复用上一次的 ActionGraph 进行分析。 这个分析过程完全在内存中完成所以如果整个工程无需重新构建即便是几万个 Action也能在一秒以内分析完毕。而其他系统至少需要花费几十秒的时间来重新构建 ActionGraph。 远程缓存 增量构建极大的提升了本地研发的构建效率但有些场合它的效果不是很好例如 CI 环境通常采用“干净”的容器此时没有上一次的构建数据只能全量构建。 即使是本地研发如果从远端同步代码时修改了全局参数也会导致增量构建失效。 缓存 (Remote Cache) 与远程执行 (Remote Execution) 可以很好的解决这个问题。 前面聊到Action 满足封闭性即相同的 Action 信息一定产生相同的结果。因此可以建立 Action 到 ActionResult 的映射。为了便于索引Bazel 把 Action 信息通过 sha256 哈希算法压缩成摘要 (Digest)把 Digest 到 ActionResult 的映射存储在云端就可以实现 Action 的跨构建共享。 ​Action 共享示意图 这里的 Storage 是完全基于内容寻址的即“一个 Digest 唯一对应一个 ActionResult”内容寻址的好处是不容易污染存储空间因为修改任何一行代码会计算出不同的 Digest不用担心污染别人的 ActionResult。内容寻址的存储引擎被称为Content Addressable Storage(CAS)如果没有特别强调本文后续使用简称 CAS 来表述。 CAS 里存放的任何文件无论是 Action 的 Meta 信息还是编译产物二进制都被称为 Blob。 为保证 CAS 的存储空间被有效利用通常会使用 LRU 算法管理 CAS 里存储的 Blob当存储空间写满时最久没被访问的 Blob 就会被自动淘汰这样就保证了空间里的 Blob 是最活跃的。 Bazel 将构建拆分为独立的步骤这些步骤称为操作。每项操作都有输入、输出名称、命令行和环境变量。系统会为每个操作明确声明所需的输入和预期输出。 您可以将服务器设置为构建输出即这些操作输出的远程缓存。这些输出由输出文件名列表及其内容的哈希值组成。借助远程缓存您可以重复使用其他用户的 build 中的构建输出而不是在本地构建每个新输出。 远程构建 既然 ActionResult 可以被不同的 Bazel 任务共享说明 ActionResult 和 Action 在哪里执行并没有关系。因此Bazel 在构建时可以把 Action 发送给另一台服务器执行对方执行完向 CAS 上传 ActionResult然后本地再下载。 这种做法减少了本地执行 Action 的开销使得我们设置更高的构建并发度。 Bazel 为 Remote Cache 和 Remote Execution 设计了专门的协议 Remote Execution API用于规范协议的客户端和服务端的行为。 完整的流程如下图所示 ​可以看到Client 和 Server 的直接交互是很少的大部分情况还是和 CAS 交互这部分采用了增量的设计Client 先调用 findMissingBlobs 接口该接口的请求参数是一堆 Blob Digest 列表返回值是 CAS 缺失的 Digest 列表。这样 Client 只上传这些 Blob可以减少网络传输的浪费。 Remote Execution API 是一套通用的远程执行协议客户端部分由 Bazel 实现服务端部分可自行定制。Bazel 团队开发两款开源实现分别是 Bazel Remote(CAS) 和 Buildfarm (Remote Executoin CAS)除此之外也有 BuildbarnBuildgrid 等开源实现以及 EngflowBuildbuddy 这样的企业版。 企业版除了提供更稳定弹性的远程执行服务外通常还提供数据分析能力用户可以根据自己的条件选择合适的开源软件或企业版服务。 外部依赖缓存 (repository_cache) 前面我们主要分析了基于 Action 的增量构建缓存和远程执行机制。现在让我们看看 Bazel 是如何管理外部依赖的。 大部分项目都没法避免引入第三方的依赖项。构建系统通常提供了下载第三方依赖的能力。为了避免重复下载Bazel 要求在声明外部依赖的时候需要记录外部依赖的 hash例如下面的这种形式 Bazel 会将下载的依赖以 CAS 的方式存储在内置的 repository_cache 目录下。你可以通过bazel info repository_cache 命令查看目录的位置。 Bazel 认为通过 checksum 机制外部依赖应该是全局共享的因此无论你的本地有多少个工程哪怕使用的是不同的 Bazel 版本都可以共享一份外部依赖。 除此之外Bazel 也支持通过 1.0.0 这样的 SerVer 版本号来声明依赖这是 Bazel6.0 版本加入的功能也是官方推荐使用的具体做法可以查看官网 相关部分。 如何高效使用 Bazel Bazel 为了正确性和高性能做了很多优秀的设计那么我们如何正确的使用这些能力让我们的构建性能“起飞”呢 我们将从本地研发和 CI pipeline 两种场景进行分析。 本地研发 本地研发通常采用默认的 Bazel 配置即可无需为增量构建和 repository_cache 做额外配置Bazel 默认就处理的很好。 使用时应该信任 bazel 的增量构建机制即便是从远端仓库同步了代码也可以直接 build无须先通过 bazel clean 清理环境。 至于 Remote Cache 和 Remote Execution则需要结合网络状况和 Action 的执行开销决定是否开启参数是 --remote_cache 和 --remote_execution。 正确开启 bazel 的 remote 能力 正确开启 remote_cache 和 remote_execution 对构建效率有显著作用但网络或 Action 特性也可能导致收益不明显甚至劣化。 举个例子说明使用 remote_cache 的利弊 我们假设 Action 的执行时间是 a上传缓存和下载缓存的时间分别是 b 和 c 缓存命中率是μ。如果不使用 remote cache耗时恒定为 a如果使用 remote cache 命中缓存耗时是 c不命中则是 a b 结合命中率可以求出耗时的数学期望是 μc (1 - μ)(a b)。也就是说只有 μc (1 - μ)(a b) a才有收益。 例如 Action 执行时间是 500ms上传产物时间是 200ms下载产物时间是 100ms缓存命中率是 30% 代入到式子中0.3 * (500 200 - 100)ms 180ms 实践中我们不一定能对 Action 做如此精细的数据分析但可以根据网络状况大致估算。Bazel 提供了精细化的控制方式可以控制某一种类型的 Action 是否启用 remote_cache例如 针对 CppLink 类型的 Action 禁用了 remote_cache 能力其他类型则可以正常使用。甚至还可以通过 no-remote-cache-upload设置为只禁止上传缓存不禁止下载缓存。 对于缓存的精细化设置属于比较高级的功能Bazel 暂时没有过多开放相关能力相关的文档也不全。或许我们可以期待一下未来能使用更方便的配置来管理。 缓存命中率调优 上面的例子可以看出Action 的缓存命中率直接决定了 remote cache 的收益如何优化缓存命中率呢 前文介绍原理时我们知道 Action 由 inputs 和 commands 组成inputs 指执行 Action 所需的目录结构和文件内容。而 commands 包括了参数 (args), 执行路径 (workdir) 和环境变量 (envs)。 当缓存命中率不符合预期时我们需要对 Action 的详情进行调试。 bazel 的 --execution_log_binary_file 参数可以把 Action 的详细信息打印到文件里。 对比两次构建的 Action 详情就可以知道是什么参数发生了变化。 该参数导出的原始信息是二进制格式有一些特殊字符如下图所示 ​ 可以借助 bazel 的 execution_log_parser 工具把它变成更可读的形式 该工具需要源码编译 bazel 使用 parser 工具把 log 变成可读形式, 转换后的文件如下图所示 ​转换后的 execution_log 之后就可以用文本对比工具对两次构建生成的 execution_log 进行对比。 CI pipeline 再来看到 CI 场景如果你在公司里搭建了持续集成流水线则需要考虑更多的东西。在公司内网的模式下CI 的网络往往不再是瓶颈我们应该完整的使用 Remote Cache 和 Remote Execution 的能力。 搭建 Remote Execution 服务 使用 Remote 能力的前提是部署支持 Remote Execution 协议的服务一般来说开源产品 buildfarm 或 buildbarn 就足够使用了如果对性能和数据分析有更加极致的要求可以考虑企业版产品或者基于 Remote Execution API 协议自研。 Remote Execution 服务的架构设计是一个很大也很有趣的话题。篇幅关系本文不过多深入细节但提供几点设计要求可以参考 Remote Execution 服务通常包括 scheduler 和 worker 组件集群规模较小时单 scheduler 可以调度所有 Action而规模较大时需要多 scheduler 协同这是一个很大的挑战。 scheduler 的职责是把 Action 调度给 最合适 的 worker并且分派的过程 越快越好。 如何衡量任务调度的好与坏一方面尽量让 Action 均匀分布避免排队时间过长另一方面尽量利用 worker 的本地文件缓存减少重复的文件下载。 不同客户端发来的相同 Action可以考虑在服务端进行合并。 不同类型的 worker需要根据系统的负载进行弹性伸缩以确保资源的高效利用。 客户端调度增强 除了 Remote Execution 服务另一块需要注意的地方是客户端调度。不同于本地构建CI 场景为了追求强隔离性往往以实时运行 Docker Container 的方式提供构建环境。也就是说构建环境不包含上一次构建的数据。 这种模式对于 Bazel 构建很不友好不仅外部依赖要重新下载而且增量编译功能也无法使用。但我们也有办法尽可能的加快构建速度。 CI 环可复用的要素 首先是使用 Remote Cache 和 Remote Execution 服务在没有增量构建的场景下Remote Cache 和 Remote Execution 提供的优化效果是非常夸张的根据我的观察提速普遍在 70% 以上甚至能达到 90%。 其次是缓存本地数据例如 trivas CI 这样的流水线编排系统就支持对特定目录进行缓存。它的原理是把目录打包上传到对象存储下次构建时再下载下来。我们可以将 Bazel 的 repository_cache 和 action_local_cache 相关的目录进行缓存下次构建就可以直接复用。 如果条件允许的话甚至可以要求流水线提供常驻容器这样 Bazel 的进程都可以长期保留着下次构建时直接 Attach 到已有的容器上执行命令即可。这种方式有望在 CI pipeline 场景实现秒级构建这是多么酷的一件事情啊 不过常驻容器对安全性也带来了一定的挑战企业具体采用那种方案也应该因实际情况而异。 总结 本文从原理方面介绍了 Bazel 高性能的原因从实践方面针对本地研发和 CI pipeline 两种场景给出了建议。 Bazel 在设计时非常注重“增量”“缓存”和“并行”这是高性能的 基础。而 Bazel 官方推出并维护了不同语言的构建规则也保证了构建过程时封闭可靠的这是高性能的 前提。除此之外针对工作空间的完整 ActionGraph 的内存缓存机制 (skyframe)使得 Bazel 对大型项目拥有秒级的构建速度这也是其他主流构建系统远远达不到的。 在实际使用中我们不仅需要深度了解 Bazel 的缓存和远程执行机制也需要根据不同的场景配置不同的参数。本地场景需要关注网络和缓存命中率以决定是否开启远端缓存和远端执行能力。CI 场景则需要关心流水线的调度能力尽可能的提升数据的复用。 相关资料来源 bazel官方中文文档 bazel官方中文文档网址2 Bazel学习笔记 如何评价 Google 开源的 Bazel Bazel使用了解 编译构建工具-bazel 如何挖掘 Bazel 的极致性能
http://www.pierceye.com/news/133267/

相关文章:

  • 江汉网站建设用js做网站登录
  • wordpress做购物网站河南省建设工程造价协会网站
  • wex5可以做网站吗爱射影院网站建设中
  • 网站建设多选题百度文库做好中心网站建设工作总结
  • 网站开发都用phpwordpress文章内图片幻灯片
  • 岳阳网站建设企业绿色大气漂亮dedecms茶叶企业网站
  • 网站建设使用虚拟主机的优点与缺点做百科网站
  • 网站被墙是谁做的电影网站模板
  • 合肥建设网官方网站网页设计网站制作公司
  • 外贸网站建设评价网站的营销方案
  • 邯郸专业做wap网站中国设计网址导航
  • 邯郸移动网站建设价格官方网站车联网是谁做
  • 哪个网站可以做高像素动图个人网站排版设计
  • 多少网站域名采用中文做一个电子商务网站在哪里做
  • 家装设计学校沈阳网站建设优化企业
  • 网站开发公司售后服务触屏端网站开发
  • 建设银行网站注销吗网页制作作品
  • 家具网站建设目的及功能定位网页游戏在哪里制作
  • 高端网站开发步骤网站设计制作如何评价
  • 漳州企业网站建设制作做发型的网站
  • 承包酒席可以做网站吗网站建设小组的运营模式
  • 保定网站建设公司哪家好酒店网站建设必要性
  • 电子商务网站建设设计报告建网站免费软件
  • 广州高端优秀网站改版设计公司网页编辑框
  • 摄影网站的需求分析wordpress英文版变成中文版
  • 网站营销公司wordpress 无效的文章类型
  • 网站一级页面标题怎么做茶网站设计素材下载
  • 网站建设费用计入什么科目淘宝网站开发店铺什么类别
  • 四川平昌县建设局网站怎么把网站维护
  • 成都教育行业网站建设工业和信息化部反诈中心发短信