2016-03-11 11 views
5

Consentitemi di avere un'intestazione, ad esempio #include <GL/gl.h>. Contiene sottoinsieme di funzioni API OpenGL. Ho bisogno di qualcosa di simile:Come verificare se la funzione è dichiarata nell'ambito globale al momento della compilazione

static_assert(has_glDrawArraysIndirect::value, "There is no glDrawArraysIndirect"); 

O ancora meglio:

PFNGLDRAWARRAYSINSTANCEDPROC ptr_glDrawArraysIndirect = ptr_to_glDrawArraysIndirect::ptr; 

Dove ptr_to_glDrawArraysIndirect::ptr srotola al puntatore a glDrawArraysIndirect se è definito o ad una funzione stub stub_glDrawArraysIndirect altrimenti.

Il mio sistema operativo di destinazione è molto specifico. Qualsiasi soluzione basata su linker (come GetProcAddress o dlsym) non funziona per me, poiché non esiste un linker dinamico. Più del mio driver non fornisce glXGetProcAdrresswglGetProcAddress, in pratica non esiste un modo per interrogare il puntatore in fase di esecuzione in base al nome della funzione (in realtà, voglio implementare un meccanismo del genere).

Qualche idea?

+1

Se non esiste alcun collegamento dinamico, deve essere collegato staticamente. Quindi o la funzione esiste al momento della compilazione o no. E dal momento che sarà determinato dal contenuto di un header, puoi solo guardare attraverso quello. –

+0

@Nicol Bolas: questo è quello che stavo facendo da molto tempo. Poiché il driver è in fase di sviluppo, sono stanco di aggiornare il mio codice. Voglio risolverlo una volta in generale. – ivaigult

risposta

5

Ecco una risposta che può rilevarlo in fase di compilazione e produrre un valore booleano. Funziona creando una funzione template con lo stesso nome in un namespace e quindi utilizzando lo spazio dei nomi all'interno della funzione is_defined(). Se esiste il reale glDrawArraysIndirect(), avrà la preferenza sulla versione del modello. Se si commenta la prima dichiarazione di glDrawArraysIndirect(), si attiverà l'asserzione statica nella parte inferiore.

Test on GodBolt

#include <type_traits> 

enum GLenum {}; 

void glDrawArraysIndirect(GLenum, const void*); 

namespace detail { 
    struct dummy; 

    template<typename T> 
    dummy& glDrawArraysIndirect(T, const void*); 
} 

constexpr bool is_defined() 
{ 
    using namespace detail; 
    using ftype = decltype(glDrawArraysIndirect(GLenum(), nullptr)); 
    return std::is_same<ftype, void>(); 
} 

static_assert(is_defined(), "not defined"); 

Con un piccolo trucco è possibile effettuare la funzione personalizzata il modello e utilizzare un trucco simile

ideone.com

#include <type_traits> 
#include <iostream> 

//#define USE_REAL 

enum GLenum {TEST}; 

typedef void (*func_type)(GLenum, const void*); 

#ifdef USE_REAL 
void glDrawArraysIndirect(GLenum, const void*); 
#endif 

namespace detail { 
    struct dummy {}; 

    template<typename T = dummy> 
    void glDrawArraysIndirect(GLenum, const void*, T = T()) 
    { 
     std::cout << "In placeholder function" << std::endl; 
    } 

} 

void wrapDraw(GLenum x, const void* y) 
{ 
    using namespace detail; 
    glDrawArraysIndirect(x, y); 
} 

#ifdef USE_REAL 
void glDrawArraysIndirect(GLenum, const void*) 
{ 
    std::cout << "In real function" << std::endl; 
} 
#endif 

int main() 
{ 
    wrapDraw(TEST, nullptr); 
} 
+1

Questo è esattamente quello che sto cercando. Hai fatto la mia giornata, grazie! – ivaigult

+0

Wow, questa magia è esattamente ciò di cui ho bisogno. –

+0

In realtà, per il secondo esempio non è necessario lo spazio dei nomi o l'argomento del modello fittizio o predefinito. Lascia che il tipo generico 'T' prenda il posto di' GLenum' e verrà selezionato dietro quello reale in risoluzione di sovraccarico. –

2

Includere l'espressione sizeof(::function) da qualche parte. (Se la funzione esiste allora chiedere la dimensione del puntatore alla funzione è una cosa perfettamente valida da fare).

Sarà benigno in fase di esecuzione e :: impone l'utilizzo dello function dichiarato nell'ambito globale.

Ovviamente, se function non esiste nell'ambito globale, la compilazione avrà esito negativo.

Insieme con altri errori, il compilatore emetterà un errore specifico se si dovesse scrivere qualcosa sulle linee di

static_assert(sizeof(::function), "There is no global function");

+0

'static_assert (sizeof (:: function)," Non esiste una funzione globale ");' –

+0

@RSahu: ti dispiace se finisco la risposta? – Bathsheba

+0

Certo che no. Vai avanti. –

1

Il mio sistema operativo di destinazione è molto specifica. Qualsiasi soluzione basata sul linker (come GetProcAddress o dlsym) non funziona per me, poiché non esiste un linker dinamico.

Si tratta di un sistema integrato o di un sistema operativo ridotto in modo spoglio che gira su hardware standard del PC?

Più che, il mio autista non fornisce né glXGetProcAdrress wglGetProcAddress, in fondo non c'è alcun modo per interrogare puntatore in fase di esecuzione in base al nome funzione

L'abiliy per interrogare puntatori a funzione in fase di esecuzione non lo fa dipende dalla presenza di un linker dinamico. Questi due sono completamente ortogonali e anche un'implementazione OpenGL embedded puramente staticamente collegata può offrire un'interfaccia GetProcAddress semplicemente soddisfacente. Invece di provare a risolvere in qualche modo il problema in fase di compilazione o di collegamento, preferirei affrontare il problema implementando un GetProcAddress per il driver OpenGL; puoi farlo anche se il driver è disponibile come solo una libreria statica in formato binario. Fase 1:

Creazione di stub di puntatori a funzione per ogni funzione OpenGL, inizializzata staticamente su NULL e attribuito collegamento debole. Collegalo a una libreria statica che puoi chiamare gl_null_stubs o simile.

Creare una funzione GetProcAddress che per ogni funzione OpenGL restituisca il puntatore al simbolo della funzione nell'ambito della funzione di compilazione della funzione.

Ora collega il tuo strano driver OpenGL con la libreria stubs e l'implementazione GetProcAddress. Per ogni funzione, il debole collegamento dello stub avrà la precedenza sul simbolo della libreria statica. Per tutti i simboli OpenGL non presenti nel driver, gli stub prenderanno il sopravvento.

Qui: Ora si dispone di una libreria di driver OpenGL che ha un'implementazione GetProcAddress. Non è stato difficile, vero?

1

Come verificare se viene dichiarata la funzione in ambito globale al momento della compilazione? Il mio sistema operativo di destinazione è molto specifico ...

Una possibile soluzione potrebbe essere, se si utilizza un recente GCC -probabilmente come un cross-compilatore per il sistema operativo di destinazione strano e ABI per personalizzare il gcc (o g++ etc ...) con la propria estensione MELT.

MELT è un linguaggio di dominio specifico, implementato come plug-in GCC software gratuito (principalmente su Linux), per personalizzare il compilatore GCC.

Problemi correlati