2014-07-25 11 views
5

Próbuję rozwiązać problem w bibliotece innej firmy. Problem polega na tym, że biblioteka używa zagnieżdżonych funkcji GCC ukrytych w makrze, a Clang nie obsługuje funkcji zagnieżdżonych i nie ma takich planów (por., Clang Bug 6378 - error: illegal storage class on function).Przepisz makro GCC z zagnieżdżoną funkcją Clang?

Oto makro to punkt ból dla mnie i Clang:

#define RAII_VAR(vartype, varname, initval, dtor) \ 
    /* Prototype needed due to http://gcc.gnu.org/bugzilla/show_bug.cgi?id=36774 */ \ 
    auto void _dtor_ ## varname (vartype * v); \ 
    void _dtor_ ## varname (vartype * v) { dtor(*v); } \ 
    vartype varname __attribute__((cleanup(_dtor_ ## varname))) = (initval) 

A oto jak jego używane (z komentarzy w kodzie):

* void do_stuff(const char *name) 
* { 
*  RAII_VAR(struct mything *, thing, find_mything(name), ao2_cleanup); 
*  if (!thing) { 
*   return; 
*  } 
*  if (error) { 
*   return; 
*  } 
*  do_stuff_with_thing(thing); 
* } 

The Clang User Manua l stany używać C++ i funkcja lambda do emulacji. Nie jestem pewien, czy jest to najlepsza strategia, a projekt C prawdopodobnie będzie miał , a nie akceptować łatkę w C++ (prawdopodobnie najpierw wyskoczą i upuści mnie).

Czy istnieje sposób na przepisanie makra, aby był on (1) bardziej dostosowany do Clanga i (2) zachowuje pierwotną funkcję semantyczną?

+0

Kolejnym sprawcą jest GLIBC. Zobacz [Dlaczego dostaję: "# error" glibc nie może być skompilowany bez optymalizacji "", kiedy próbujesz skompilować GNU libc z GNU CC?] (Http://sourceware.org/glibc/wiki/FAQ#Why_do_I_get:.60.23 error_.22glibc_cannot_be_compiled_without_optimization.22.27.2C_when_trying_to_compile_GNU_libc_with_GNU_CC.3F) – jww

+2

Nawiasem mówiąc, to Asterisk: http://svn.asterisk.org/svn/asterisk/trunk/include/asterisk/utils.h Jeśli zdobyć szczęk do kompilacji Makro RAII_VAR, popychając ten wkład w górę strumienia byłoby niezwykle docenione. Jest kilka otwartych problemów. –

+2

O ile, oczywiście, jeden z Was nie wniósł poprawki do tego problemu: https://issues.asterisk.org/jira/browse/ASTERISK-20850 :-) –

Odpowiedz

6

Clang nie obsługuje GCC zagnieżdżone funkcje, ale ma wsparcie Objective C-style "blocks", nawet w trybie C: (?)

void f(void * d) { 
    void (^g)(void *) = ^(void * d){ }; 
    g(d); 
} 

Trzeba powołać go z komendy clang zamiast gcc, a także przekazać -fblocks -lBlocksRuntime do kompilatora.

Nie możesz użyć bloku jako wartości cleanup bezpośrednio, ponieważ musi to być nazwa funkcji, więc (kradnąc pomysły z here) musisz dodać warstwę pośrednią. Zdefiniować pojedynczą funkcję, aby oczyścić void klocki, i uczynić zmienna RAII'd blokktóry chcesz uruchomić na końcu zakresu:

typedef void (^cleanup_block)(void); 
static inline void do_cleanup(cleanup_block * b) { (*b)(); } 

void do_stuff(const char *name) { 
    cleanup_block __attribute__((cleanup(do_cleanup))) __b = ^{ }; 
} 

Ponieważ bloki tworzą zamknięcia można następnie umieść operacje na zmiennych do czyszczenia bezpośrednio wewnątrz że blok ...

void do_stuff(const char *name) { 
    struct mything * thing; 
    cleanup_block __attribute__((cleanup(do_cleanup))) __b = ^{ ao2_cleanup(thing); }; 
} 

... i to powinno działać na końcu zakresu, jak poprzednio, są wywoływane przez porządki na bloku. Przestawiać makro i dodać __LINE__ więc działa z wieloma deklaracjami:

#define CAT(A, B) CAT_(A, B) 
#define CAT_(A, B) A##B 

#define RAII_VAR(vartype, varname, initval, dtor) \ 
    vartype varname = (initval); \ 
    cleanup_block __attribute__((cleanup(do_cleanup))) CAT(__b_, __LINE__) = ^{ dtor(varname); }; 

void do_stuff(const char *name) { 
    RAII_VAR(struct mything *, thing, NULL, ao2_cleanup); 
    ... 

coś takiego w każdym razie.

Powiązane problemy