Получить constexpr без запуска программы

Dec 04 2020

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

Я мог бы заставить свою программу записать в file.cpp следующее:

#include "mylibrary.hpp"
int main()
{
    std::cout << std::is_trivially_copyable<A>::value << '\n';
    std::cout << std::is_trivially_copyable<B>::value << '\n';
    std::cout << std::is_trivially_copyable<C>::value << '\n';
    std::cout << std::is_trivially_copyable<D>::value << '\n';
}

затем скомпилируйте и запустите этот код и проанализируйте вывод. Есть ли лучший способ получить эту информацию? (важна производительность). Может ли libclang это сделать?

ОБНОВЛЕНИЕ из-за комментариев:

Что касается проблемы XY: то, что я пытаюсь сделать, это написать программу (называемую rust-bindgen) на языке rust, которая получает путь к заголовочному файлу C ++ в качестве аргумента и генерирует привязки rust-c ++ для этого файла заголовка. Мне нужно генерировать привязки по-разному в зависимости от того, можно ли тривиально копировать / перемещать тип.

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

TL; DR: как я могу написать быструю функцию ржавчины, которая принимает две строки в качестве аргумента и возвращает логическое значение: первая строка - это путь к файлу заголовка C ++, вторая строка - это имя типа, определенного в указанном файле заголовка. Он должен возвращать логическое значение, указывающее, можно ли копировать тип тривиально или нет.

Ответы

2 ecatmur Dec 04 2020 at 04:56

Вам нужно будет скомпилировать код, по крайней мере, для IR. Это связано с тем, что тривиальность класса C ++ может зависеть от произвольно сложных вычислений, входные данные которых могут включать атрибуты платформы, доступные заголовки, определения препроцессора, параметры компилятора и т. Д., Которые, таким образом, могут выполняться только компилятором C ++.

Если вы вызываете clang как двоичный файл, опция для испускания IR есть, clang -S -emit-llvmи вы затем захотите проанализировать вывод LLVM IR; например для

#include <type_traits>
struct A {};
struct B { B(B const&); };
struct C { ~C(); };
struct D { D(D const&) = default; };
int a = std::is_trivially_copyable<A>::value;
int b = std::is_trivially_copyable<B>::value;
int c = std::is_trivially_copyable<C>::value;
int d = std::is_trivially_copyable<D>::value;

их:

@a = dso_local local_unnamed_addr global i32 1, align 4, !dbg !0
@b = dso_local local_unnamed_addr global i32 0, align 4, !dbg !6
@c = dso_local local_unnamed_addr global i32 0, align 4, !dbg !10
@d = dso_local local_unnamed_addr global i32 1, align 4, !dbg !12
 ^ variable name                             ^ initializer

Если вы хотите использовать libclang, вам нужно будет вызвать EmitLLVMOnlyAction, предоставив модуль, из которого вы затем сможете извлечь определения GlobalVariable. См .: Метод создания LLVM IR.