Holen Sie sich constexpr, ohne das Programm auszuführen

Dec 04 2020

Ich habe eine Bibliothek (sowohl als Quelle als auch kompiliert) und schreibe ein Programm (nicht mit dieser Bibliothek verknüpft), das wissen muss, ob ein Typ in der Bibliothek z. B. trivial kopierbar ist oder nicht.

Ich könnte mein Programm dazu bringen, Folgendes in file.cpp zu schreiben:

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

Kompilieren Sie dann diesen Code, führen Sie ihn aus und analysieren Sie die Ausgabe. Gibt es einen besseren Weg, um diese Informationen zu erhalten? (Leistung ist wichtig). Kann libclang das tun?

UPDATE wegen Kommentaren:

In Bezug auf das XY-Problem: Ich versuche, ein Programm (namens rust-bindgen) in rust zu schreiben, das den Pfad einer C ++ - Headerdatei als am-Argument abruft und rust-c ++ - Bindungen für diese Headerdatei generiert. Ich muss die Bindungen unterschiedlich generieren, je nachdem, ob der Typ trivial kopierbar / verschiebbar ist.

Ich habe also einen Pfad zu einer C ++ - Headerdatei und muss wissen, ob ein bestimmter Typ, der in dieser Headerdatei definiert ist, trivial kopierbar ist. Der obige Ansatz funktioniert, ist jedoch langsam, da die Datei file.cpp kompiliert wird.

TLDR: Wie kann ich eine schnelle Rostfunktion schreiben, die zwei Zeichenfolgen als Argument verwendet und einen Bool zurückgibt: Die erste Zeichenfolge ist der Pfad zu einer C ++ - Headerdatei, die zweite Zeichenfolge ist der Name eines in dieser Headerdatei definierten Typs. Es sollte ein Bool zurückgegeben werden, das angibt, ob der Typ trivial kopierbar ist oder nicht.

Antworten

2 ecatmur Dec 04 2020 at 04:56

Sie müssen den Code zumindest im IR kompilieren. Dies liegt daran, dass die Trivialität einer C ++ - Klasse von einer willkürlich komplizierten Berechnung abhängen kann, deren Eingaben Plattformattribute, verfügbare Header, Präprozessordefinitionen, Compileroptionen usw. enthalten können, die daher nur von einem C ++ - Compiler ausgeführt werden können.

Wenn Sie clang als Binärdatei aufrufen, können clang -S -emit-llvmSie IR ausgeben, und Sie möchten dann die LLVM-IR-Ausgabe analysieren. zum Beispiel für

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

Die IR ist:

@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

Wenn Sie libclang verwenden möchten, müssen Sie EmitLLVMOnlyAction aufrufen und ein Modul angeben, aus dem Sie die GlobalVariable-Definitionen extrahieren können. Siehe: Methode zum Erstellen von LLVM-IR