非 bazel 包的 bazel 工作区

bazel workspace for non-bazel packages

我正在使用这样的包 graphviz as part of a service and to use it I begin the 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 构建过程的一部分,这样如果它不存在,它将被获取并放在正确的位置?

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

来自 https://graphviz.org/download/source/ the 2.49.1 release is available at 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 将有效地用指向该路径的 local_repository 替换 http_archive。但是,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