• bazel构建项目案例(第三方库,编译成库,运行案例)


            使用bazel构建项目,包含如何引入外部库(项目中引入了opencv和编译的tensorflow lite库),如何编译成动态库和静态库,以及如何调用编译好的库。

            项目根目录的所有文件结构如下图所示。项目的构建由图中红色框起来的文件描述,其中蓝色的方框是生成的静态库和动态库(它们是从其他目录复制过来的)

    一、构建外部库文件

            首先,构建WORKSPACE,即确定外部需要引入的库,如下:

    1. # 确定外部的opencv库路径
    2. new_local_repository(
    3. name = "opencv4",
    4. path = "/usr/local", # opencv安装的目录
    5. build_file = "opencv4.BUILD",
    6. )
    7. # 确定外部的tensorflow lite库路径
    8. new_local_repository(
    9. name = "tensorflow_lite",
    10. path = "/home/chentao/tensorflowlite", # tensorflow lite编译成功所在目录
    11. build_file = "tensorflowLite.BUILD",
    12. )

    下图是我这边opencv和tensorflow lite库目录结构,看实际图片更容易理解(文件太多了,用tree显示更不好看,手画的将就看看)。

     然后再构建WORKSPACE中提及到的opencv4.BUILD和tensorflowLite.BUILD文件,这里容易出错。为了更好理解可以结合上述图片仔细理清路径问题。

     opencv4.BUILD文件:

    1. # 构建opencv外部引入目标
    2. cc_library(
    3. name = "opencv4",
    4. srcs = glob(["lib/libopencv*.so*"]),
    5. hdrs = glob(["include/opencv4/opencv2/**/*.h*"]),
    6. includes = ["include/opencv4/"],
    7. visibility = ["//visibility:public"],
    8. linkstatic = 0, # 默认值是1,表示链接的是静态库,否则就是动态库(有疑问不确定)
    9. )

    tensorflowLite.BUILD文件:

    1. # 构建tensorflow lite外部引入库目标
    2. cc_library(
    3. name = "tensorflow_lite",
    4. srcs = glob(["libs/libtensorflowlite.so"]),
    5. hdrs = glob(["include/**/*.h"]), # 等同于glob(["include/tensorflow/lite/**/*.h"]) + glob(["include/flatbuffers/**/*.h"])
    6. includes = ["include/"],
    7. visibility = ["//visibility:public"],
    8. linkstatic = 0,
    9. )

            至此,外部的库文件已经确定好了,现在可以直接使用它们了。

    二、src目录的BUILD文件

            这个文件的BUILD文件包含了使用opencv和tensorflow lite库,编译成动态、静态库等等目标。提供常规使用的语法很具有参考意义。详细内容看注释。

    1. # 构建facepose目标
    2. cc_library(
    3. name = "facepose",
    4. srcs = glob(["*.cpp"]), # 遍历当前目录所有.cpp文件
    5. hdrs = glob(["*.h*"]), # 遍历当前目录所有含有.h字符的文件
    6. deps = [
    7. "@tensorflow_lite//:tensorflow_lite",
    8. "@opencv4//:opencv4",
    9. ],
    10. visibility = ["//visibility:public"], # 完全公开,本worksapce及其他workspace都可以访问
    11. #visibility = ["//visibility:private"], # 私有,仅同一package内可访问
    12. #visibility = ["@my_repo//foo/bar:__pkg__"], # 表示指定的my_repo项目的//foo/bar的package内所有Targets可以访问
    13. #visibility = ["//foo/bar:__subpackages__"], # 表示指定的//foo/bar的package及其内部所有package的所有Targets可以访问
    14. )
    15. # 构建facepose动态库目标
    16. cc_binary(
    17. name = "libfacepose.so", # name一定要命名成lib*.so形式,否则会出现gcc定位错误(查到资料看到的,未验证)
    18. srcs = glob(["*.cpp"]) + glob(["*.h*"]),
    19. # hdrs = glob(["*.h*"]), # cc_binary中没有hdrs属性
    20. deps = [
    21. "@tensorflow_lite//:tensorflow_lite",
    22. "@opencv4//:opencv4",
    23. ],
    24. linkshared=True, # 由这个属性指定生成动态库目标文件
    25. visibility = ["//visibility:public"],
    26. )
    27. # 构建facepose静态库目标
    28. cc_library(
    29. name = "faceposestatic", # 生成结果会自动在前面加上lib,在后面加上.a
    30. srcs = glob(["*.cpp"]),
    31. hdrs = glob(["*.h*"]),
    32. deps = [
    33. "@tensorflow_lite//:tensorflow_lite",
    34. "@opencv4//:opencv4",
    35. ],
    36. linkstatic=True, # 由这个属性指定生成静态库目标文件
    37. visibility = ["//visibility:public"],
    38. )
    39. # 构建facepose头文件目标
    40. cc_library(
    41. name = "faceposeHeader",
    42. hdrs = glob(["*.h*"]),
    43. visibility = ["//visibility:public"],
    44. )
    45. # 将当前目录的所有含有.h文件变成可以看见属性
    46. #exports_files(glob(["*.h*"]))

    三、demo目录的BUILD文件

            该目录是如果用bazel编译成可执行文件,以及如何使用动/静态库等等。详细内容看注释。

    1. # 构建引用facepose动态库目标:如果在showAll目标中使用,需要先在程序根目录运行:
    2. # bazel build //src:libfacepose.so命令,将生成的.so文件拷贝到对应路径(参考libfacepose.so的路径)
    3. cc_import(
    4. name="dllfacepose",
    5. shared_library="libfacepose.so",
    6. deps = ["//src:faceposeHeader"],
    7. )
    8. # 构建引用facepose静态库目标:如果在showAll目标中使用,需要先在程序根目录运行:
    9. # bazel build //src:faceposestatic命令,将生成的.a文件拷贝到对应路径(参考libfaceposestatic.a的路径)
    10. cc_import(
    11. name="staticFacepose",
    12. static_library="libfaceposestatic.a",
    13. deps = ["//src:faceposeHeader"],
    14. # 文件所在BUILD中添加了exports_files(glob(["*.h*"])),下面属性和deps属性作用相同
    15. #hdrs = ["@//src:DetectionPostProcess.hpp","@//src:FaceDetection.hpp",其他头文件也要加],
    16. )
    17. # 构建可执行程序目标
    18. cc_binary(
    19. name = "showAll",
    20. srcs = ["showAll.cpp"],
    21. deps = [
    22. "//src:facepose", # 引入其他Packages的构建的目标
    23. #":dllfacepose", # 使用自己编译的动态库文件
    24. #":staticFacepose", # 使用自己编译的静态库文件。上述三种只须选其中一种即可
    25. "@opencv4//:opencv4", # 引入外部opencv库
    26. "@tensorflow_lite//:tensorflow_lite"
    27. ],
    28. linkopts = ["-lpthread"], # 链接多线程库
    29. copts = ["-Isrc"], # 添加src路径:不添加,则showAll.cpp文件中就需要#include "src/IrisLandmark.hpp"方式
    30. #copts = ["-std=c++14"]+["-Iinclude"], # 指定C++14标准编译,并在当前或者依赖包的include目录下寻找头文件
    31. )
    32. # 构建可执行文件,用于测试opencv
    33. cc_binary(
    34. name = "test_opencv",
    35. srcs = ["test_opencv.cpp"],
    36. deps = [
    37. "@opencv4//:opencv4",
    38. ],
    39. )

    四、编译上述目标命令

            下面所有命令都是在根目录下的终端执行,即和WORKSPACE同目录。      

            最简单的工程是用test_opencv.cpp测试opencv调用是否成功。命令如下:

    1. # 编译
    2. bazel build //demo:test_opencv
    3. # 执行
    4. ./bazel-bin/demo/test_opencv

            编译动/静态的命令,如下所示:

    1. # 动态库
    2. bazel build //src:libfacepose.so
    3. # 静态库
    4. bazel build //src:faceposestatic

           编译可调用opencv和tensorflow lite库文件的可执行文件,命令如下:

    1. # 编译
    2. bazel build //demo:showAll
    3. # 执行
    4. ./bazel-bin/demo/showAll

            贴出test_opencv.cpp和showAll.cpp文件,里面有#include注意项,被坑过。

    test_opencv.cpp

    1. #include
    2. #include "opencv2/highgui.hpp"
    3. int main(int argc, char* argv[]) {
    4. cv::VideoCapture cap("../face_pose.avi");
    5. bool success = cap.isOpened();
    6. if (success == false)
    7. {
    8. std::cerr << "Cannot open the camera." << std::endl;
    9. return 1;
    10. }
    11. while (success)
    12. {
    13. cv::Mat rframe, frame;
    14. success = cap.read(rframe); // read a new frame from video
    15. if (success == false)
    16. break;
    17. cv::imshow("Face detector", rframe);
    18. if (cv::waitKey(1) == 27)
    19. break;
    20. }
    21. cap.release();
    22. cv::destroyAllWindows();
    23. return 0;
    24. }

    showAll.cpp

    1. #include
    2. #include "opencv2/highgui.hpp"
    3. #include "IrisLandmark.hpp" // 这里注意是否是 #include "src/IrisLandmark.hpp" ,看编译选项是否有copts = ["-Isrc"]
    4. #define SHOW_FPS (1)
    5. #if SHOW_FPS
    6. #include
    7. #endif
    8. int main(int argc, char* argv[]) {
    9. my::IrisLandmark irisLandmarker("./models");
    10. cv::VideoCapture cap("./face_pose.avi");
    11. bool success = cap.isOpened();
    12. if (success == false)
    13. {
    14. std::cerr << "Cannot open the camera." << std::endl;
    15. return 1;
    16. }
    17. #if SHOW_FPS
    18. float sum = 0;
    19. int count = 0;
    20. #endif
    21. while (success)
    22. {
    23. cv::Mat rframe, frame;
    24. success = cap.read(rframe); // read a new frame from video
    25. if (success == false)
    26. break;
    27. cv::flip(rframe, rframe, 1);
    28. #if SHOW_FPS
    29. auto start = std::chrono::high_resolution_clock::now();
    30. #endif
    31. irisLandmarker.loadImageToInput(rframe);
    32. irisLandmarker.runInference();
    33. for (auto landmark: irisLandmarker.getAllFaceLandmarks()) {
    34. cv::circle(rframe, landmark, 2, cv::Scalar(0, 255, 0), -1);
    35. }
    36. for (auto landmark: irisLandmarker.getAllEyeLandmarks(true, true)) {
    37. cv::circle(rframe, landmark, 2, cv::Scalar(0, 0, 255), -1);
    38. }
    39. for (auto landmark: irisLandmarker.getAllEyeLandmarks(false, true)) {
    40. cv::circle(rframe, landmark, 2, cv::Scalar(0, 0, 255), -1);
    41. }
    42. #if SHOW_FPS
    43. auto stop = std::chrono::high_resolution_clock::now();
    44. auto duration = std::chrono::duration_cast(stop - start);
    45. float inferenceTime = duration.count() / 1e3;
    46. sum += inferenceTime;
    47. count += 1;
    48. int fps = (int) 1e3/ inferenceTime;
    49. cv::putText(rframe, std::to_string(fps), cv::Point(20, 70), cv::FONT_HERSHEY_PLAIN, 3, cv::Scalar(0, 196, 255), 2);
    50. #endif
    51. cv::imshow("Face detector", rframe);
    52. if (cv::waitKey(10) == 27)
    53. break;
    54. }
    55. #if SHOW_FPS
    56. std::cout << "Average inference time: " << sum / count << "ms " << std::endl;
    57. #endif
    58. cap.release();
    59. cv::destroyAllWindows();
    60. return 0;
    61. }

  • 相关阅读:
    计算机网络——计算机网络体系结构
    Python二进制文件转换为文本文件
    图论第3天----第841题、第463题
    ConflictingBeanDefinitionException
    three.js 第八节 - gltf加载器、解码器
    【用unity实现100个游戏之16】Unity程序化生成随机2D地牢游戏2(附项目源码)
    mac的Jupyter怎么使用
    【智能优化算法-飞蛾扑火优化算法】基于水循环混合飞蛾扑火优化算法求解约束的工程优化问题附matlab代码WCMFO
    PMP每日一练 | 考试不迷路-9.13(包含敏捷+多选)
    luckysheet的一点使用心得
  • 原文地址:https://blog.csdn.net/qq_31112205/article/details/126641927