Генерация констант во время компиляции из содержимого файла

#rust #rust-cargo

#Ржавчина #rust-груз

Вопрос:

Допустим, у меня есть файл с некоторыми константами в нем. Этот файл, вероятно, поступает из другого сервиса и может отличаться для разных сценариев. Теперь я хочу выжать из своей программы все до последней капли производительности, хочу, чтобы компилятор выполнял как можно больше оптимизации, и я бы скомпилировал проект для каждого сценария отдельно, если это необходимо.

Есть ли способ взять файл во время компиляции, превратить его в код rust с помощью некоторой логики преобразования, например, сгенерировать некоторые константы и скомпилировать результат (все внутри инструментария rust, никакой другой генерации кода)?

Комментарии:

1. То, как вы это сделаете, во многом зависит от того, как выглядят эти константы. Это просто числа и массивы или что-то в этом роде?

2. const fn пользователи пока не могут получить доступ к файлам, но в конечном итоге могут. Если это возможно, вы могли бы написать const MY_CONST: MyType = get_value_from_file(); const get_value_from_file() { ... }

3. @Hadus, как вы сказали, «пока не удается получить доступ к файлам «. Является ли это частью повестки дня Rust в настоящее время?

4. @TristanStorch: Недавно было несколько разговоров по этому поводу, но ничего определенного, AFAICT.

Ответ №1:

Если вы запишете build.rs файл в корень вашего ящика, он будет компилироваться и запускаться при каждой компиляции ящика.

Обычно он используется для создания привязок C и тому подобного, но ничто не мешает вам использовать его в своих целях.

Обычно это build.rs создает исходный файл Rust где-то в выходном каталоге, считывая переменную OUT_DIR среды:

 fn main() {
    println!("cargo:rerun-if-changed=build.rs");
    println!("cargo:rerun-if-changed=data.txt");

    let out_dir = std::env::var_os("OUT_DIR").unwrap();
    let path = std::path::Path::new(amp;out_dir).join("test.rs");
    std::fs::write(amp;path, "pub fn test() { todo!() }").unwrap();
}
 

Затем исходный код включается в ваш проект, обычно в его собственном модуле с:

 mod test {
    include!(concat!(env!("OUT_DIR"), "/test.rs"));
}
 

Комментарии:

1. Несмотря на то, что речь идет о генерации кода, это, по-видимому, лучшее, что можно сделать на данный момент. Не на 100% доволен, но что поделаешь. Примет этот ответ.

Ответ №2:

Вы могли бы просто сгенерировать исходные файлы rust, содержащие ваши константы.

Эти части могут быть на любом языке:

  1. Создайте данные, которые вы хотите использовать в качестве констант
  2. Сохраните их в исходных файлах rust в качестве констант, используя некоторые манипуляции со строками

В rust:

  1. pub mod const_file в path/to/mod.rs
  2. use path::to::const_file::MY_CONST;
  3. cargo build ваша программа rust

Пример для массива констант, который вы получаете из python:

 array = [0, 10, 34]
const_file_str = f"pub const MY_CONST: [u16; 3] = {array};n"

with open("path/to/const_file.rs", "w") as rust_file:
    rust_file.write(const_file_str)

 

Комментарии:

1. Мне пришлось сделать что-то подобное, чтобы преодолеть ограничение на оценку const. (инициализация const не может длиться вечно)

2. Как я писал в своем первоначальном вопросе, я хочу остаться в области инструментов rust и, в частности, избегать «другой генерации кода»

3. Другой ответ лучше, но вы могли бы выполнить первые два шага в build.rs файле.