Как я могу активировать функции во всех моих ящиках? - PullRequest
0 голосов
/ 03 ноября 2018

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

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

Чтобы уточнить, что именно я хочу, вот пример , который я также воспроизведу ниже:

Существует три ящика: основной, мусорный ящик, ящик и два ящика для библиотек, которые называются «средние» и «общие». Вот соответствующие части соответствующих файлов:

main.rs

extern crate common;
extern crate middle;

fn main() {
    common::check!();

    middle::run();

    println!("done");
}

основной груз.томл

[dependencies]

[dependencies.common]
path = "libs/common"

[dependencies.middle]
path = "libs/middle"

[features]
default = []
invariant-checking = []
logging = []

среднего lib.rs

extern crate common;

pub fn run() {
    common::check!();

    common::run();
}

середина Cargo.toml

[dependencies]

[dependencies.common]
path = "../common"

[features]
default = []
invariant-checking = []
logging = []

общие lib.rs

#[macro_export]
macro_rules! check {
    () => {{
        if cfg!(feature = "invariant-checking") {
            println!("invariant-checking {}:{}", file!(), line!());
        }
        if cfg!(feature = "logging") {
            println!("logging {}:{}", file!(), line!());
        }
    }};
}

pub fn run() {
    check!()
}

и, наконец, обычные Cargo.toml

[dependencies]

[features]
default = []
invariant-checking = []
logging = []

Когда я запускаю cargo run --features "invariant-checking,logging", я получаю следующий вывод

invariant-checking src\main.rs:5
logging src\main.rs:5
done

но вы хотите, чтобы он входил в средний и общий, а также. Как я могу преобразовать этот проект так, чтобы он это сделал, и все же позволить мне получить только «готово» в качестве результата, изменив только одно место?

Ответы [ 2 ]

0 голосов
/ 03 ноября 2018

У определений макросов в их текущей форме есть проблема: код внутри макроса вставляется при каждом использовании макроса, а затем компилируется в контексте, в котором он был встроен. Так как вы используете проверки во время выполнения, такие как

if cfg!(feature = "invariant-checking")

это означает, что вам нужно определить объекты в каждом ящике, где вы используете макрос. С другой стороны, в самом ящике common эта функция никогда не запрашивается и, таким образом, является избыточной.

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

#[cfg(feature = "invariant-checking")]
macro_rules! check_invariant {
    () => ( println!("invariant-checking {}:{}", file!(), line!()); )
}

#[cfg(not(feature = "invariant-checking"))]
macro_rules! check_invariant {
    () => ()
}

#[cfg(feature = "logging")]
macro_rules! logging {
    () => ( println!("logging {}:{}", file!(), line!()); )
}

#[cfg(not(feature = "logging"))]
macro_rules! logging {
    () => ()
}

#[macro_export]
macro_rules! check {
    () => ( check_invariant!(); logging!(); )
}

Таким образом, вам нужно будет только определить элемент в ящике common, как и должно быть. Пока вы используете только одну версию этого ящика, включение и выключение флага имеет глобальный эффект.

0 голосов
/ 03 ноября 2018

Как включить и отключить функции нескольких ящиков?

A Cargo.toml может добавлять функции, которые транзитивно включают другие функции, которым разрешено принадлежать к зависимостям.

Например, в Cargo.toml ящика, который зависит от ящиков foo и bar:

[dependencies]
foo = "0.1"
bar = "0.1"

[features]
default = []
invariant-checking = [ "foo/invariant-checking", "bar/invariant-checking" ]
logging = [ "foo/logging", "bar/logging" ]

В этот ящик добавлены функции invariant-checking и logging. Включение их транзитивно включает соответствующие функции ящиков foo и bar, так что

cargo build --features=logging,invariant-checking

включит функции logging и invariant-checking в этом ящике, а также в его зависимостях foo и bar.

В вашем конкретном случае вы, вероятно, хотите, чтобы main транзитивно включал функции middle и common, а для middle транзитивно включал функции common.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...