Obtenga constexpr sin ejecutar el programa

Dec 04 2020

Tengo una biblioteca (tanto como fuente como compilada) y estoy escribiendo un programa (no vinculado a esta biblioteca) que necesita saber si algún tipo en la biblioteca es, por ejemplo, trivialmente copiable o no.

Podría hacer que mi programa escriba lo siguiente en 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';
}

luego compile y ejecute este código y analice la salida. ¿Existe una mejor manera de obtener esta información? (el rendimiento es importante). ¿Libclang puede hacer eso?

ACTUALIZAR debido a los comentarios:

Con respecto al problema XY: Lo que estoy tratando de hacer es escribir un programa (llamado rust-bindgen) en rust, que obtiene la ruta de un archivo de encabezado de C ++ como argumento am y genera enlaces rust-c ++ para ese archivo de encabezado. Necesito generar los enlaces de manera diferente dependiendo de si el tipo es trivialmente copiable / reubicable.

Así que tengo una ruta a un archivo de encabezado de C ++ y necesito saber si un tipo determinado que está definido en ese archivo de encabezado se puede copiar trivialmente. El enfoque anterior funciona, pero es lento, porque implica compilar file.cpp.

TLDR: ¿Cómo puedo escribir una función rust rápida, que toma dos cadenas como argumento y devuelve un bool? La primera cadena es la ruta a un archivo de encabezado de C ++, la segunda cadena es el nombre de un tipo definido en dicho archivo de encabezado. Debería devolver un bool que diga si el tipo se puede copiar trivialmente o no.

Respuestas

2 ecatmur Dec 04 2020 at 04:56

Necesitará compilar el código, al menos en IR. Esto se debe a que la trivialidad de una clase C ++ puede depender de un cálculo arbitrariamente complicado cuyas entradas pueden incluir atributos de plataforma, encabezados disponibles, definiciones del preprocesador, opciones del compilador, etc., que por lo tanto, solo puede ser realizado por un compilador C ++.

Si está invocando clang como un binario, la opción para emitir IR es clang -S -emit-llvmy luego querrá analizar la salida LLVM IR; por ejemplo para

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

ellos son:

@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 desea utilizar libclang, deberá invocar EmitLLVMOnlyAction dando un módulo del que luego puede extraer las definiciones de GlobalVariable. Ver: Método para crear LLVM IR