Obtenez constexpr sans exécuter le programme

Dec 04 2020

J'ai une bibliothèque (à la fois comme source et compilée) et j'écris un programme (non lié à cette bibliothèque) qui a besoin de savoir si un type de la bibliothèque est par exemple trivialement copiable ou non.

Je pourrais faire en sorte que mon programme écrive ce qui suit dans 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';
}

puis compilez et exécutez ce code et analysez la sortie. Existe-t-il une meilleure façon d'obtenir ces informations? (la performance est importante). La libclang peut-elle faire ça?

MISE À JOUR à cause des commentaires:

En ce qui concerne le problème XY: ce que j'essaie de faire, c'est d'écrire un programme (appelé rust-bindgen) dans rust, qui obtient le chemin d'un fichier d'en-tête C ++ en tant qu'argument am et génère des liaisons rust-c ++ pour ce fichier d'en-tête. J'ai besoin de générer les liaisons différemment selon que le type est trivialement copiable / relocalisable.

J'ai donc un chemin vers un fichier d'en-tête C ++ et j'ai besoin de savoir si un type donné défini dans ce fichier d'en-tête est facilement copiable. L'approche ci-dessus fonctionne, mais est lente, car elle implique la compilation de file.cpp.

TLDR: Comment puis-je écrire une fonction de rusticité rapide, qui prend deux chaînes comme argument et renvoie un booléen: La première chaîne est le chemin vers un fichier d'en-tête C ++, la deuxième chaîne est le nom d'un type défini dans ledit fichier d'en-tête. Il doit renvoyer un booléen indiquant si le type est copiable ou non.

Réponses

2 ecatmur Dec 04 2020 at 04:56

Vous allez avoir besoin de compiler le code, au moins en IR. En effet, la trivialité d'une classe C ++ peut dépendre d'un calcul arbitrairement compliqué dont les entrées peuvent inclure des attributs de plate-forme, des en-têtes disponibles, des définitions de préprocesseur, des options de compilateur etc., qui ne peuvent donc être effectués que par un compilateur C ++.

Si vous invoquez clang en tant que binaire, l'option pour émettre IR est clang -S -emit-llvmet vous voudrez alors analyser la sortie LLVM IR; par exemple pour

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

l'IR est:

@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

Si vous souhaitez utiliser libclang, vous devrez invoquer EmitLLVMOnlyAction en donnant un module dont vous pourrez ensuite extraire les définitions GlobalVariable. Voir: Méthode pour créer LLVM IR