Pobierz constexpr bez uruchamiania programu

Dec 04 2020

Mam bibliotekę (zarówno jako źródłową, jak i skompilowaną) i piszę program (niepowiązany z tą biblioteką), który musi wiedzieć, czy jakiś typ w bibliotece jest np. Trywialnie kopiowalny, czy nie.

Mogę sprawić, by mój program zapisał w pliku 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';
}

następnie skompiluj i uruchom ten kod i przeanalizuj dane wyjściowe. Czy jest lepszy sposób na uzyskanie tych informacji? (wydajność jest ważna). Czy libclang może to zrobić?

UPDATE z powodu komentarzy:

Odnośnie problemu XY: To, co próbuję zrobić, to napisać program (o nazwie rust-bindgen) w rdzeniu, który pobiera ścieżkę pliku nagłówkowego C ++ jako argument am i generuje powiązania rust-c ++ dla tego pliku nagłówkowego. Muszę generować powiązania inaczej w zależności od tego, czy typ jest trywialnie kopiowalny / relokowalny.

Mam więc ścieżkę do pliku nagłówkowego C ++ i muszę wiedzieć, czy dany typ zdefiniowany w tym pliku nagłówkowym można w prosty sposób skopiować. Powyższe podejście działa, ale jest powolne, ponieważ wymaga kompilacji pliku.cpp.

TLDR: Jak mogę napisać funkcję szybkiej rdzy, która przyjmuje dwa ciągi jako argument i zwraca wartość bool: pierwszy ciąg to ścieżka do pliku nagłówkowego C ++, drugi ciąg to nazwa typu zdefiniowanego we wspomnianym pliku nagłówkowym. Powinien zwrócić wartość bool, która mówi, czy typ można w prosty sposób skopiować, czy nie.

Odpowiedzi

2 ecatmur Dec 04 2020 at 04:56

Będziesz musiał skompilować kod, przynajmniej do IR. Dzieje się tak, ponieważ trywialność klasy C ++ może zależeć od arbitralnie skomplikowanych obliczeń, których dane wejściowe mogą obejmować atrybuty platformy, dostępne nagłówki, definicje preprocesora, opcje kompilatora itp., Które mogą być zatem wykonywane tylko przez kompilator C ++.

Jeśli wywołujesz clang jako plik binarny, opcja emitowania IR jest, clang -S -emit-llvma wtedy będziesz chciał przeanalizować wyjście LLVM IR; na przykład dla

#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;

IR to:

@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

Jeśli chcesz użyć libclang, będziesz musiał wywołać EmitLLVMOnlyAction, podając moduł, z którego możesz następnie wyodrębnić definicje GlobalVariable. Zobacz: Metoda tworzenia LLVM IR