Необязательные зависимости в проекте Rust Bazel

Я начинаю с проекта Bazel на Rust, без Cargo. Я пытаюсь настроить необязательную зависимость с функцией контроля функций.

У меня есть настройка crates_vendor:

crates_vendor(
    name = "crates_io",
    cargo_lockfile = ":Cargo.Bazel.lock",
    mode = "remote",
    packages = {
        "tonic": crate.spec(version = "*"),
        "serde": crate.spec(version = "1.0"),
        "serde_json": crate.spec(version = "1.0"),
    },
    repository_name = "crates_io",
    tags = ["manual"],
)

Теперь моя библиотека Rust определяется как:

rust_library(
    name = "foo",
    srcs = glob("**/*.rs"),
    deps = [
        "@crates_io//:serde",
        "@crates_io//:serde_json",
    ],
)

Это @crates_io//:serde_json, что я хочу показать.

Код Cargo.toml для этого будет:

[dependencies]
serde_json = { version = "1.0", optional = true }

[features]
json = ["dep:serde_json"]

Однако, как я уже говорил, это проект, не связанный с Cargo.

Каким будет правильный способ добиться этого? Пытался покопаться в документации, но не могу понять.

bazel.build/docs/configurable-attributes ?
eggyal 29.04.2024 23:23
Почему Python в конце концов умрет
Почему Python в конце концов умрет
Последние 20 лет были действительно хорошими для Python. Он прошел путь от "просто языка сценариев" до основного языка, используемого для написания...
0
1
113
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

В Bazel нельзя выбирать функции библиотеки в потребителе библиотеки, функции должны быть определены в самой библиотеке.

Итак, в вашем случае есть два варианта.

1. Определите отдельную библиотеку для каждого набора функций.

Вы можете просто определить библиотеку, используя те же источники, но с разными зависимостями.

rust_library(
    name = "foo",
    srcs = glob("**/*.rs"),
    deps = [
        "@crates_io//:serde",
    ],
)

rust_library(
    name = "foo_json",
    crate_name = "foo",
    crate_features = ["foo_json"],
    srcs = glob("**/*.rs"),
    deps = [
        "@crates_io//:serde",
        "@crates_io//:serde_json",
    ],
)

Обратите внимание, что вам нужно пройти crate_name, если имя цели Bazel не совпадает с именем ящика. Также обратите внимание, что вам, возможно, придется установить свои функции и в библиотеке, поскольку rustc также должен знать о включенных функциях.

Это простой и достаточно надежный способ работы с функциями.

2. Используйте настраиваемые атрибуты

Это позволит определить вашу библиотеку только один раз. И включать и выключать функции во время сборки. Обратной стороной является то, что эти функции можно включить только глобально. При любом использовании библиотеки foo будет использоваться версия с json или без него.

load("@rules_rust//rust:defs.bzl", "rust_library")
load("@bazel_skylib//rules:common_settings.bzl", "bool_flag")

# Here we define a boolean flag, that can later use on command line
bool_flag(
    name = "use_json",
    build_setting_default = False,
)

# The flag from above turn on and off the named config setting
config_setting(
    name = "foo_json",
    flag_values = {":use_json": "true"},
)

# based on the config setting we can select features
# we will pass to the compiler...
foo_features = select({
    ":foo_json": ["json"],
    "//conditions:default": [],
})

# .. and the dependncies, that we need.
foo_optional_deps = select({
    ":foo_json": [
        # "@crates_io//:serde_json",
    ],
    "//conditions:default": [],
})

# After we selected features and dependencies, we
# define the library using them.
rust_library(
    name = "foo",
    srcs = ["src/lib.rs"],
    crate_features = foo_features,
    deps = [
    ] + foo_optional_deps
)

Например. если у меня есть инструмент, зависящий от библиотеки foo,

rust_binary(
    name = "tool",
    srcs = ["src/main.rs"],
    deps = [
        "//foo:foo",
    ],
)

В этом примере, чтобы включить функцию json, вы можете использовать командную строку:

bazel run //tool:tool --//foo:use_json

Как выбрать?

Если вы хотите для разных последующих проектов использовать разные функции foo, то лучше всего подойдет первый подход.

Если вы создаете программное обеспечение с глобально включенными некоторыми функциями (например, бесплатная версия с отключенными некоторыми функциями), второй подход может работать лучше.

Уже было что-то с двумя rust_library, но crate_name — очень приятное дополнение: мне не придется менять импорт в Rust, если я решу использовать другой набор функций. Тоже пытался поиграться с флагами, но не получилось. Очень хорошо. Оба варианта нравятся!

Victor 02.05.2024 10:25

Возможно, стоит заметить, что второй подход более точно имитирует Cargo, который выполняет унификацию функций для определения единого унифицированного набора функций для каждого ящика в графе зависимостей; это, в свою очередь, является причиной того, почему функции должны быть только аддитивными, чтобы они не нарушали работу тех функций, которые, как вы не ожидали, будут включены по требованию в другом месте графика.

eggyal 06.05.2024 12:54

Другие вопросы по теме