【问题标题】:bazel workspace for non-bazel packages非 bazel 包的 bazel 工作区
【发布时间】:2021-10-26 07:39:36
【问题描述】:

我正在使用包 graphviz 作为服务的一部分并使用它,我开始像这样的 bazel WORKSPACE 文件

new_local_repository(
    name = "graphviz",
    path = "/usr/local/Cellar/graphviz/2.49.1",
    build_file_content = """
package(default_visibility = ["//visibility:public"])
cc_library(
    name = "headers",
    srcs = glob(["**/*.dylib"]),
    hdrs = glob(["**/*.h"])
)
"""
)

...

它的问题在于它依赖于graphviz 被下载、预安装并出现在路径/usr/local/Cellar/graphviz/2.49.1 中。有没有办法让它成为 bazel 构建过程的一部分,这样如果它不存在,它将被提取并放在正确的位置?

【问题讨论】:

    标签: graphviz bazel


    【解决方案1】:

    您可以使用http_archive 下载graphviz 的发布档案之一: https://docs.bazel.build/versions/main/repo/http.html#http_archive

    来自https://graphviz.org/download/source/ 的2.49.1 版本可在https://gitlab.com/api/v4/projects/4207231/packages/generic/graphviz-releases/2.49.1/graphviz-2.49.1.tar.gz 获得

    load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
    http_archive(
      name = "graphviz",
      url = "https://gitlab.com/api/v4/projects/4207231/packages/generic/graphviz-releases/2.49.1/graphviz-2.49.1.tar.gz",
      strip_prefix = "graphviz-2.49.1",
      sha256 = "ba1aa7a209025cb3fc5aca1f2c0114e18ea3ad29c481d75e4d445ad44e0fb0f7",
      build_file_content = """
    
    package(default_visibility = ["//visibility:public"])
    cc_library(
        name = "headers",
        srcs = glob(["**/*.dylib"]),
        hdrs = glob(["**/*.h"])
    )
    
    """,
    )
    

    要回答问题的“如果它不存在”部分,我不知道有一种直接的方法可以在本地安装的东西和下载的东西之间自动切换。 http_archive 将始终下载存档,new_local_repository 将始终使用本地文件。

    --override_repository 标志,它将存储库替换为本地存储库,例如--override_repository=graphviz=/usr/local/Cellar/graphviz/2.49.1 将有效地将http_archive 替换为指向该路径的local_repository。但是,bazel 会期望该位置已经存在 WORKSPACE 文件和 BUILD 文件(即,无法指定 build_file_content

    您可以在 WORKSPACE 文件中指定两个存储库规则,然后使用某种间接方式、Starlark 标志和 select() 使用命令行标志在存储库之间切换。虽然它有点复杂,而且也不是自动的。像这样的:

    工作空间:

    http_archive(
      name = "graphviz-download",
      ...,
    )
    new_local_repository(
      name = "graphviz-installed",
      ...,
    )
    
    load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
    http_archive(
        name = "bazel_skylib",
        urls = [
            "https://github.com/bazelbuild/bazel-skylib/releases/download/1.1.1/bazel-skylib-1.1.1.tar.gz",
            "https://mirror.bazel.build/github.com/bazelbuild/bazel-skylib/releases/download/1.1.1/bazel-skylib-1.1.1.tar.gz",
        ],
        sha256 = "c6966ec828da198c5d9adbaa94c05e3a1c7f21bd012a0b29ba8ddbccb2c93b0d",
    )
    load("@bazel_skylib//:workspace.bzl", "bazel_skylib_workspace")
    bazel_skylib_workspace()
    

    构建(例如在 //third_party/graphviz 中):

    load("@bazel_skylib//rules:common_settings.bzl", "bool_flag")
    bool_flag(
        name = "use-installed-graphviz",
        build_setting_default = False,
    )
    
    config_setting(
      name = "installed",
      flag_values = {
        ":use-installed-graphviz": "True",
      }
    )
    
    alias(
      name = "headers",
      actual = select({
        ":installed": "@graphviz-installed//:headers",
        "//conditions:default": "@graphviz-download//:headers",
      })
    )
    

    那么你的代码依赖//third_party/graphviz:headers,默认别名会指向下载的版本,标志--//third_party/graphviz:use-installed-graphviz会切换到安装的版本:

    $ bazel cquery --output build //third_party/graphviz:headers
    alias(
      name = "headers",
      actual = "@graphviz-download//:headers",
    )
    
    $ bazel cquery --output build //third_party/graphviz:headers --//third_party/graphviz:use-installed-graphviz
    alias(
      name = "headers",
      actual = "@graphviz-installed//:headers",
    )
    

    另一种选择是编写(或查找)一个自定义存储库规则,该规则结合了http_archivelocal_repository 的功能,但这可能是一项相当大的工作。

    通常我认为大多数人只是使用http_archive 并下载依赖项,如果有离线或缓存的特定需求,则有--distdir 用于将已下载的工件用于远程存储库规则:https://docs.bazel.build/versions/main/guide.html#distribution-files-directories

    编辑:将 rules_foreign_cc 与 graphviz 一起使用的示例:

    工作空间:

    load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
    
    http_archive(
        name = "rules_foreign_cc",
        sha256 = "69023642d5781c68911beda769f91fcbc8ca48711db935a75da7f6536b65047f",
        strip_prefix = "rules_foreign_cc-0.6.0",
        url = "https://github.com/bazelbuild/rules_foreign_cc/archive/0.6.0.tar.gz",
    )
    load("@rules_foreign_cc//foreign_cc:repositories.bzl", "rules_foreign_cc_dependencies")
    # This sets up some common toolchains for building targets. For more details, please see
    # https://bazelbuild.github.io/rules_foreign_cc/0.6.0/flatten.html#rules_foreign_cc_dependencies
    rules_foreign_cc_dependencies()
    
    http_archive(
      name = "graphviz",
      url = "https://gitlab.com/api/v4/projects/4207231/packages/generic/graphviz-releases/2.49.1/graphviz-2.49.1.tar.gz",
      strip_prefix = "graphviz-2.49.1",
      sha256 = "ba1aa7a209025cb3fc5aca1f2c0114e18ea3ad29c481d75e4d445ad44e0fb0f7",
      build_file_content = """\
    filegroup(
        name = "all_srcs",
        srcs = glob(["**"]),
        visibility = ["//visibility:public"],
    )
    """,
    )
    

    构建:

    load("@rules_foreign_cc//foreign_cc:defs.bzl", "configure_make")
    
    # see https://bazelbuild.github.io/rules_foreign_cc/0.6.0/configure_make.html
    configure_make(
        name = "graphviz",
        lib_source = "@graphviz//:all_srcs",
        out_shared_libs = ["libcgraph.so"], # or other graphviz libs
    )
    
    cc_binary(
      name = "foo",
      srcs = ["foo.c"],
      deps = [":graphviz"],
    )
    

    foo.c:

    #include "graphviz/cgraph.h"
    
    int main() {
      Agraph_t *g;
      g = agopen("G", Agdirected, NULL);
      agclose(g);
      return 0;
    }
    

    用法:

    $ bazel build foo
    INFO: Analyzed target //:foo (0 packages loaded, 2 targets configured).
    INFO: Found 1 target...
    Target //:foo up-to-date:
      bazel-bin/foo
    INFO: Elapsed time: 0.229s, Critical Path: 0.06s
    INFO: 7 processes: 5 internal, 2 linux-sandbox.
    INFO: Build completed successfully, 7 total actions
    

    【讨论】:

    • 只有一个问题.. bazel 如何知道如何构建它,因为它是一个非 bazel 包?
    • 您可以使用new_local_repositoryhttp_archivebuild_filebuild_file_content 属性来指定与该存储库一起使用的BUILD 文件
    • 你能说得更具体些吗? Graphvuz 是一个非 bazel 库,所以它没有构建文件。它使用 cmake。
    • 所以通常你需要编写一个 BUILD 文件来构建 graphiz,并将其用于build_file。如果构建很复杂,您可能需要 fork graphviz,或在您自己的存储库中提供它。或者也许有人已经发布了适当的 BUILD 文件。另一种选择是使用 rules_foreign_cc,它使 bazel 能够构建基于 cmake 的项目:github.com/bazelbuild/rules_foreign_cc bazelbuild.github.io/rules_foreign_cc/0.6.0/cmake.html 这可能是一个不错的起点。
    • 我是这方面的新手,你能在答案中提供如何做到这一点吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-24
    • 1970-01-01
    相关资源
    最近更新 更多