Могут ли макросы proc определить цель вызывающей компиляции?

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

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

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

Однако rustc не устанавливает никаких переменных окружения; и Cargo ограничены немногими. В частности, некоторая ключевая информация (например, целевая архитектура / операционная система и т. Д.) Вообще отсутствует.

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

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

2 ответа

Решение

Я несколько неэлегантно решил эту проблему, рекурсивно перейдя во второй вызов макроса proc, где первый вызов добавляет #[cfg_attr] атрибуты с буквальными логическими параметрами, к которым затем можно получить доступ во втором вызове:

#[cfg_attr(all(target_os = "linux"), my_macro(linux = true ))]
#[cfg_attr(not(target_os = "linux"), my_macro(linux = false))]
// ...

Хакер, но работает.

Я нашел другое решение:

Вместо того, чтобы генерировать код в зависимости от такого флага, вы можете генерировать код для всех ОС и использовать #[cfg(...)]внутри цитируемого кода.

      quote! {
    #[cfg(linux)]
    {
        // linux specific stuff
    }

    #[cfg(not(linux))]
    {
        // not linux specific stuff
    }
}

Это, наверное, чище.

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