Tensorflow的Bazel编程(二)

2023-11-01

转自:http://blog.csdn.net/langb2014/article/details/54312697

安装官网:https://bazel.build/versions/master/docs/tutorial/Java.html

Build Java

创建一个java项目,然后

[python]  view plain  copy
  1. cd /home/mi/git/TF_pro/Bazel/project  
在终端运行:

[python]  view plain  copy
  1. $ mkdir -p src/main/java/com/example  
  2. $ cat > src/main/java/com/example/ProjectRunner.java <<EOF  
  3. package com.example;  
  4.   
  5. public class ProjectRunner {  
  6.     public static void main(String args[]) {  
  7.         Greeting.sayHi();  
  8.     }  
  9. }  
  10. EOF  
  11. $ cat > src/main/java/com/example/Greeting.java <<EOF  
  12. package com.example;  
  13.   
  14. public class Greeting {  
  15.     public static void sayHi() {  
  16.         System.out.println("Hi!");  
  17.     }  
  18. }  
  19. EOF  
在项目根目录下建一个BUILD文件:

[python]  view plain  copy
  1. java_binary(  
  2.     name = "my-runner",  
  3.     srcs = glob(["**/*.java"]),  
  4.     main_class = "com.example.ProjectRunner",  
  5. )  
然后build
[python]  view plain  copy
  1. bazel build //:my-runner  
进入生成的文件夹
[python]  view plain  copy
  1. bazel-bin  
运行可执行文件
[python]  view plain  copy
  1. my-runner  
输出:Hi!
成功构建了第二个Bazel项目了!
随着项目的增加,我们讲java项目拆成两个部分独立构建,同时设置它们之间的依赖关系。
重新构建一下BUILD文件:

[python]  view plain  copy
  1. java_binary(  
  2.     name = "my-other-runner",  
  3.     srcs = ["src/main/java/com/example/ProjectRunner.java"],  
  4.     main_class = "com.example.ProjectRunner",  
  5.     deps = [":greeter"],  
  6. )  
  7.   
  8. java_library(  
  9.     name = "greeter",  
  10.     srcs = ["src/main/java/com/example/Greeting.java"],  
  11. )  
虽然源文件是一样的,但是现在Bazel将采用不同的方式来构建:首先是构建 greeter 库,然后是构建my-other-runner。可以在构建成功后立刻运行//:my-other-runner
[python]  view plain  copy
  1. $ bazel run //:my-other-runner  
  2. INFO: Found 1 target...  
  3. Target //:my-other-runner up-to-date:  
  4.   bazel-bin/my-other-runner.jar  
  5.   bazel-bin/my-other-runner  
  6. INFO: Elapsed time: 2.454s, Critical Path: 1.58s  
  7.   
  8. INFO: Running command line: bazel-bin/my-other-runner  
  9. Hi!  
更多的包

对于更大的项目,我们通常需要将它们拆分到多个目录中。你可以用类似//path/to/directory:target-name的名字引用在其他BUILD文件定义的目标。假设src/main/java/com/example/有一个cmdline/子目录,包含下面的文件:


 
 
[python] view plain copy
  1. $ mkdir -p src/main/java/com/example/cmdline  
  2. $ cat > src/main/java/com/example/cmdline/Runner.java <<EOF  
  3. package com.example.cmdline;  
  4.   
  5. import com.example.Greeting;  
  6.   
  7. public class Runner {  
  8.     public static void main(String args[]) {  
  9.         Greeting.sayHi();  
  10.     }  
  11. }  
  12. EOF  
Runner.java依赖com.example.Greeting,因此我们需要在src/main/java/com/example/cmdline/BUILD构建文件中添加相应的依赖规则:

 
 
[python] view plain copy
  1. # src/main/java/com/example/cmdline/BUILD  
  2. java_binary(  
  3.     name = "runner",  
  4.     srcs = ["Runner.java"],  
  5.     main_class = "com.example.cmdline.Runner",  
  6.     deps = ["//:greeter"]  
  7. )  
然而,默认情况下构建目标都是 私有 的。也就是说,我们只能在同一个BUILD文件中被引用。这可以避免将很多实现的细节暴漏给公共的接口,但是也意味着我们需要手工允许runner所依赖的//:greeter目标。就是类似下面这个在构建runner目标时遇到的错误:

 
 
[python] view plain copy
  1. $ bazel build //src/main/java/com/example/cmdline:runner  
  2. ERROR: /home/user/gitroot/my-project/src/main/java/com/example/cmdline/BUILD:2:1:  
  3.   Target '//:greeter' is not visible from target '//src/main/java/com/example/cmdline:runner'.  
  4.   Check the visibility declaration of the former target if you think the dependency is legitimate.  
  5. ERROR: Analysis of target '//src/main/java/com/example/cmdline:runner' failed; build aborted.  
  6. INFO: Elapsed time: 0.091s  
可用通过在BUILD文件增加visibility = level属性来改变目标的可间范围。下面是通过在~/gitroot/my-project/BUILD文件增加可见规则,来改变greeter目标的可见范围:

 
 
[python] view plain copy
  1. java_library(  
  2.     name = "greeter",  
  3.     srcs = ["src/main/java/com/example/Greeting.java"],  
  4.     visibility = ["//src/main/java/com/example/cmdline:__pkg__"],  
  5. )  
这个规则表示//:greeter目标对于//src/main/java/com/example/cmdline包是可见的。现在我们可以重新构建runner目标程序:
[python] view plain copy
  1. $ bazel run //src/main/java/com/example/cmdline:runner  
  2. INFO: Found 1 target...  
  3. Target //src/main/java/com/example/cmdline:runner up-to-date:  
  4.   bazel-bin/src/main/java/com/example/cmdline/runner.jar  
  5.   bazel-bin/src/main/java/com/example/cmdline/runner  
  6. INFO: Elapsed time: 1.576s, Critical Path: 0.81s  
  7.   
  8. INFO: Running command line: bazel-bin/src/main/java/com/example/cmdline/runner  
  9. Hi!  

如果你查看 bazel-bin/src/main/java/com/example/cmdline/runner.jar 的内容,可以看到里面只包含了Runner.class,并没有保护所依赖的Greeting.class:

[python]  view plain  copy
  1. $ jar tf bazel-bin/src/main/java/com/example/cmdline/runner.jar  
  2. META-INF/  
  3. META-INF/MANIFEST.MF  
  4. com/  
  5. com/example/  
  6. com/example/cmdline/  
  7. com/example/cmdline/Runner.class  
这只能在本机正常工作(因为Bazel的runner脚本已经将greeter jar添加到了classpath),但是如果将runner.jar单独复制到另一台机器上讲不能正常运行。如果想要构建可用于部署发布的自包含所有依赖的目标,可以构建runner_deploy.jar目标(类似<target-name>_deploy.jar以_deploy为后缀的名字对应可部署目标)。


 
 
[python] view plain copy
  1. $ bazel build //src/main/java/com/example/cmdline:runner_deploy.jar  
  2. INFO: Found 1 target...  
  3. Target //src/main/java/com/example/cmdline:runner_deploy.jar up-to-date:  
  4.   bazel-bin/src/main/java/com/example/cmdline/runner_deploy.jar  
  5. INFO: Elapsed time: 1.700s, Critical Path: 0.23s  
runner_deploy.jar中将包含全部的依赖。


Build C++

首先创建头文件和源文件:

切记一定要先建一个WORKSPACE,这个可以为空,不然找不到工程下面的一些目录,build会报错。

在project1下

[python]  view plain  copy
  1. $ mkdir ./main  
  2. $ cat > main/hello-world.cc <<'EOF'  
  3. #include "lib/hello-greet.h"  
  4. #include "main/hello-time.h"  
  5. #include <iostream>  
  6. #include <string>  
  7.   
  8. int main(int argc, char** argv) {  
  9.   std::string who = "world";  
  10.   if (argc > 1) {  
  11.     who = argv[1];  
  12.   }  
  13.   std::cout << get_greet(who) <<std::endl;  
  14.   print_localtime();  
  15.   return 0;  
  16. }  
  17. EOF  
  18. $ cat > main/hello-time.h <<'EOF'  
  19. #ifndef MAIN_HELLO_TIME_H_  
  20. #define MAIN_HELLO_TIME_H_  
  21.   
  22. void print_localtime();  
  23.   
  24. #endif  
  25. EOF  
  26. $ cat > main/hello-time.cc <<'EOF'  
  27. #include "main/hello-time.h"  
  28. #include <ctime>  
  29. #include <iostream>  
  30.   
  31. void print_localtime() {  
  32.   std::time_t result = std::time(nullptr);  
  33.   std::cout << std::asctime(std::localtime(&result));  
  34. }  
  35. EOF  
  36. $ mkdir ./lib  
  37. $ cat > lib/hello-greet.h <<'EOF'  
  38. #ifndef LIB_HELLO_GREET_H_  
  39. #define LIB_HELLO_GREET_H_  
  40.   
  41. #include <string>  
  42.   
  43. std::string get_greet(const std::string &thing);  
  44.   
  45. #endif  
  46. EOF  
  47. $ cat > lib/hello-greet.cc <<'EOF'  
  48. #include "lib/hello-greet.h"  
  49. #include <string>  
  50.   
  51. std::string get_greet(const std::string& who) {  
  52.   return "Hello " + who;  
  53. }  
  54. EOF  
在lib下添加BUILD文件:
[python]  view plain  copy
  1. cc_library(  
  2.     name = "hello-greet",  
  3.     srcs = ["hello-greet.cc"],  
  4.     hdrs = ["hello-greet.h"],  
  5.     visibility = ["//main:__pkg__"],  
  6. )  
在main下 添加BUILD文件:

[python]  view plain  copy
  1. cc_library(  
  2.     name = "hello-time",  
  3.     srcs = ["hello-time.cc"],  
  4.     hdrs = ["hello-time.h"],  
  5. )  
  6.   
  7. cc_binary(  
  8.     name = "hello-world",  
  9.     srcs = ["hello-world.cc"],  
  10.     deps = [  
  11.         ":hello-time",  
  12.         "//lib:hello-greet",  
  13.     ],  
  14. )  

依赖传递

如果包含了一个头文件,那么需要将头文件对应的库添加到依赖中。不过,只需有添加直接依赖的库。假设三明治对应的sandwich.h文件包含了面包对应的bread.h文件,同时bread.h又包含了面粉对应的flour.h文件。但是,三明治sandwich.h文件并没有直接包含面粉flour.h文件。

BUILD文件是这样的:

[python]  view plain  copy
  1. cc_library(  
  2.     name = "sandwich",  
  3.     srcs = ["sandwich.cc"],  
  4.     hdrs = ["sandwich.h"],  
  5.     deps = [":bread"],  
  6. )  
  7.   
  8. cc_library(  
  9.     name = "bread",  
  10.     srcs = ["bread.cc"],  
  11.     hdrs = ["bread.h"],  
  12.     deps = [":flour"],  
  13. )  
  14.   
  15. cc_library(  
  16.     name = "flour",  
  17.     srcs = ["flour.cc"],  
  18.     hdrs = ["flour.h"],  
  19. )  
上面表示了 sandwich三明治库依赖bread面包库,bread又依赖flour对应的面粉库。
添加头文件路径

很多时候你可能并不希望基于工作区根路径的相对路径来包含每个头文件。因为很多已经存在的第三方库的头文件包含方式并不是基于工作区的根路径。假设有以下目录结构:

[python]  view plain  copy
  1. [workspace]/  
  2.     WORKSPACE  
  3.     third_party/  
  4.         some_lib/  
  5.             include/  
  6.                 some_lib.h  
  7.             BUILD  
  8.             some_lib.cc  

Bazel希望用third_party/some_lib/include/some_lib.h方式包含some_lib.h,但是some_lib.cc可能跟希望用"include/some_lib.h"方式包含。为了使得包含路径有效,需要在third_party/some_lib/BUILD文件中将some_lib/目录添加到头文件包含路径的搜索列表中:

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

这对于依赖的外部第三方库特别有效,因为可以避免在头文件路径中出现无关的external/[repository-name]/前缀。

添加外部库:

假设使用了Google Test。可以在WORKSPACE文件中使用new_开头的仓库相关的函数,下载依赖的GTest代码到当前仓库中:

[python]  view plain  copy
  1. new_http_archive(  
  2.     name = "gtest",  
  3.     url = "https://googletest.googlecode.com/files/gtest-1.7.0.zip",  
  4.     sha256 = "247ca18dd83f53deb1328be17e4b1be31514cedfc1e3424f672bf11fd7e0d60d",  
  5.     build_file = "gtest.BUILD",  
  6. )  
创建gtest.BUILD文件,对应Google Test的构建配置文件。配置文件中有几个需要特别注意的地方:

  • gtest-1.7.0/src/gtest-all.cc文件已经采用#include语法包含了gtest-1.7.0/src/目录中其它*.cc文件,因此需要将它排除在外(也可以只包含它一个文件,但是需要正确配置包含路径)。
  • 它的头文件在gtest-1.7.0/include/目录,需要将它添加到头文件包含路径列表中
  • GTest依赖pthread多线程库,通过linkopt选项指定。

最终的规则大概是这样:

[python]  view plain  copy
  1. cc_library(  
  2.     name = "main",  
  3.     srcs = glob(  
  4.         ["gtest-1.7.0/src/*.cc"],  
  5.         exclude = ["gtest-1.7.0/src/gtest-all.cc"]  
  6.     ),  
  7.     hdrs = glob([  
  8.         "gtest-1.7.0/include/**/*.h",  
  9.         "gtest-1.7.0/src/*.h"  
  10.     ]),  
  11.     copts = [  
  12.         "-Iexternal/gtest/gtest-1.7.0/include"  
  13.     ],  
  14.     linkopts = ["-pthread"],  
  15.     visibility = ["//visibility:public"],  
  16. )  

这是有点混乱:所有以gtest-1.7.0为前缀的其实都是生成的临时文件。我们可以通过new_http_archive函数中的strip_prefix属性来忽略它:

[python]  view plain  copy
  1. new_http_archive(  
  2.     name = "gtest",  
  3.     url = "https://googletest.googlecode.com/files/gtest-1.7.0.zip",  
  4.     sha256 = "247ca18dd83f53deb1328be17e4b1be31514cedfc1e3424f672bf11fd7e0d60d",  
  5.     build_file = "gtest.BUILD",  
  6.     strip_prefix = "gtest-1.7.0",  
  7. )  

现在gtest.BUILD简洁多了:

[python]  view plain  copy
  1. cc_library(  
  2.     name = "main",  
  3.     srcs = glob(  
  4.         ["src/*.cc"],  
  5.         exclude = ["src/gtest-all.cc"]  
  6.     ),  
  7.     hdrs = glob([  
  8.         "include/**/*.h",  
  9.         "src/*.h"  
  10.     ]),  
  11.     copts = ["-Iexternal/gtest/include"],  
  12.     linkopts = ["-pthread"],  
  13.     visibility = ["//visibility:public"],  
  14. )  

现在cc_相关的规则可以通过//external:gtest/main引用GTest了。

测试./test/hello-test.cc

[python]  view plain  copy
  1. #include "gtest/gtest.h"  
  2. #include "lib/hello-greet.h"  
  3.   
  4. TEST(FactorialTest, Negative) {  
  5.   EXPECT_EQ(get_greet("Bazel"), "Hello Bazel");  
  6. }  
./test/BUILD

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

[python]  view plain  copy
  1. cc_library(  
  2.     name = "hello-greet",  
  3.     srcs = ["hello-greet.cc"],  
  4.     hdrs = ["hello-greet.h"],  
  5.     visibility = ["//test:__pkg__"],  
  6. )  


依赖预编译的库

如果要依赖一个已经编译好的库(可能只有头文件和对应的*.so库文件),可以使用cc_library规则包装一个库对象:

[python]  view plain  copy
  1. cc_library(  
  2.     name = "mylib",  
  3.     srcs = ["mylib.so"],  
  4.     hdrs = ["mylib.h"],  
  5. )  
其它的目标就可以依赖这个包装的库对象了。

参考:

https://my.oschina.NET/chai2010/blog/674110

https://my.oschina.net/chai2010/blog/701807

https://bazel.build/versions/master/docs/tutorial/cpp.html

https://bazel.build/versions/master/docs/tutorial/java.html

https://bazel.build/versions/master/docs/bazel-user-manual.html


本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Tensorflow的Bazel编程(二) 的相关文章

随机推荐

  • Unity中设置物体的透明度

    Unity中设置物体的透明度 Unity中设置物体的透明度 不要再用Metial aa new Metial 因为不再支持 改用matial color Color red 来进行相关设置 在ANDROID端基本是不支持的 PC端目前好像还
  • ProGuard代码混淆器如何使用

    一 概述 1 ProGuard简介 背景 ProGuard 是一个免费的 Java 类文件的压缩 优化 混肴器 它删除没有用的类 字段 方法与属性 使字节码最大程度地优化 使用简短且无意义的名字来重命名类 字段和方法 使用场景 我们在工程应
  • Idea系列文章2-依赖包的引入

    Idea系列文章 IDEA 全称 IntelliJ IDEA 是java编程语言开发的集成环境 IntelliJ在业界被公认为最好的java开发工具 尤其在智能代码助手 代码自动提示 重构 JavaEE支持 各类版本工具 git svn等
  • VUE element-ui之el-tree树形控件勾选节点指定节点自动勾选(指定节点为必选项)

    产品需求 最后一级节点中列表节点为必选项 勾选列表节点之外的同级节点 列表节点自动勾选 取消列表节点勾选 其他同级节点也取消勾选 即列表节点为必选项 列表之外的节点可单独操作 勾选或取消勾选 实现步骤 HTML中定义
  • php mysql utf 8_PHP+MySQL中对UTF-8,UTF8(utf8),set names gbk 的理解

    问题一 在我们进行数据库操作时会发现 数据库中表的编码用的是utf 8 但是在进行dos命令是要使用set names gbk 一 Mysql中默认字符集设置有四级 服务器级 数据库级 表级 和字段级 前三种都是默认设置 并不代表你的字段最
  • mysql删除表数据 MySQL清空表内容 3种命令方法及比较

    一 MySQL清空表数据命令 truncate SQL语法 truncate table 表名 注意 不能与where一起使用 truncate删除数据后是不可以rollback的 truncate删除数据后会重置Identity 标识列
  • Spring Boot 学习系列(09)—自定义Bean的顺序加载

    此文已由作者易国强授权网易云社区发布 欢迎访问网易云社区 了解更多网易技术产品运营经验 Bean 的顺序加载 有些场景中 我们希望编写的Bean能够按照指定的顺序进行加载 比如 有UserServiceBean和OrderServiceBe
  • 薪酬问题手册

    薪酬问题手册 所有离职人员的缺勤扣款都不对 考勤报表 自由制的考勤日历工作时长要显示实际工作时长 考勤报表 自由制 计算月工作时长 解决在接受页面数据CompAtteMonth对象时的absenteeismTime 调整后的缺勤时长 问题
  • GiftWrapping算法求最小凸包的简单实现

    目录 前言 问题简介 基本知识 算法简介 算法简单实现过程 源代码 结语 前言 本篇文章是基于哈工大软件构造的实验一写出的 源代码也只是TurtleSoup类中一个方法 虽然不能直接使用 但其思想还是有一定的参考价值 问题简介 一组平面上的
  • Intel lock前缀指令的屏障能力

    Intel lock前缀指令除了单操作原子性的能力之外 还具备可见性和有序性 对于Intel lock前缀指令的单操作原子性和可见性 参见下面两个链接 其实本质就是锁总线或锁缓存 加上缓存一致性协议 Intel LOCK前缀指令https
  • wsl ubuntu18.04LTS 网络连接设置

    修改 etc resolv conf可以自己设置 dns 但重启 WSL 以后 手动设置的 DNS 就会被重置为默认的 细心看了一下默认的文件以后发现了问题的关键 WSL 自动在启动时自动根据系统的虚拟交换机WSL生成 etc resolv
  • 一位计算机准PhD的大四和博零

    最新个人信息可见 Home Zhuoning Guo 完整版请见 知乎 攻读PhD 大一开始有读博念头 大二计划去香港 理由 学制短 奖学金高 环境 导师和同学 容易适应 海外麻烦也申不到特别好的 如美帝Top10 牛剑 大三基于校内实验室
  • k8s1.26.6 安装gitlab

    Gitlab官方提供了 Helm 的方式在 Kubernetes 集群中来快速安装 但是在使用的过程中发现 Helm 提供的 Chart 包中有很多其他额外的配置 所以我们这里使用自定义的方式来安装 也就是自己来定义一些资源清单文件 Git
  • SimpleDateFormat多线程下的异常

    今天在生产上碰到一个怪异的问题 之前一直跑的很好的xml转object程序 在日期转化的过程中报错的 经过排查原因 原来是由于SimpleDateFormat在多线程下运行造成的结果 demo例子如下 import java text Pa
  • Ubuntu环境下安装ffmpeg

    1 创建安装 录 sudo mkdir p usr local ffmpeg lib 2 下载ffmpeg源码 Download FFmpeg 3 解压源文件 4 到指定ffmpeg目录进行配置 cd ffmpeg 4 3 2 配置 con
  • Mybatis——增删改查的实现

    注意 增删改时一定要提交事务 代码 提交事务 sqlSession commit 1 namespace 命名空间 namespace中的全限定名 包名 类名 要和Dao Mapper接口的全限定名 包名 类名 一致 2 select 选择
  • 灌电流和拉电流简介

    灌电流 sink current 对一个端口而言 如果电流方向是向其内部流动的则是 灌电流 比如一个IO通过一个电阻和一个LED连接至VCC 当该IO输出为逻辑0时能不能点亮LED 去查该器件手册中sink current参数 拉电流 so
  • Flask后端部署到云服务器

    1 本地写好代码 2 码云创建仓库 上传本地代码到创库 git init git remote add origin https gitee com 自己的仓库 git git pull origin master git add git
  • 1 在 Linux 下开机自动重启脚本(亲测)

    etc rc local 开机启动程序 把需要开机自动运行的程序写在这个脚本里 etc init d 这个目录存放的是一些脚本 一般是linux以rpm包安装时设定的一些服务的启动脚本 要重新启动 sendmail 的话 而且你的 send
  • Tensorflow的Bazel编程(二)

    转自 http blog csdn net langb2014 article details 54312697 安装官网 https bazel build versions master docs tutorial Java html