2013-04-18 3 views
2

Этот вопрос касается gcc-конструктора, компиляции & Ссылка правильная, но она НЕ запускается.GCC constructor NOT execute

Существует a.c:

UTEST_BEGIN() 
UID(a_test) 
{ 
    printf("a test"); 
    return true; 
} 
UTEST_END(a) 

b.c является simlar:

UTEST_BEGIN() 
UID(b_test) 
{ 
    printf("b test"); 
    return true; 
} 
UTEST_END(b) 

Объект код использует UID() ссылаются некоторые функции тестирования. Моя первая версия добавляет UTEST_BEGIN() UTEST_END(), чтобы заключить UID(), наконец, я понимаю, что UTEST_BGIN() UTEST_END() не требуется, когда я их изменяю, получается непредсказуемый результат.

Когда я изменяю определение UTEST_BEGIN(), UID(), UTEST_END(), у меня получается другой результат.

Основная идея исходит от can-i-auto-collect-a-list-of-function-by-c-macro!

Тест 1:

#define UTEST_BEGIN()         \ 
static const bool __m_en = true;      \ 
static struct __uti *__m_uti_head = NULL; 



bool utest_item_list_add_global(struct __uti *uti); 
#define UID(f)               \ 
static bool __uti_##f(void);           \ 
__attribute__((constructor))           \ 
static void uti_construct_##f(void)          \ 
{                  \ 
    printf("%s\n", #f); \ 
    static struct __uti __m_uti_##f = {NULL, this_file_id, __uti_##f, #f };  \ 
    utest_item_list_add_global(&__m_uti_##f);       \ 
}                  \ 
static bool __uti_##f(void) 


bool unit_test_item_pump_do(int file_id, bool (*f)(void), const char *f_name); 
#define UTEST_END(file_name)           \ 
bool unit_test_##file_name(void)          \ 
{                  \ 
    if (!__m_en)              \ 
      return true;            \ 
    struct __uti *cur;             \ 
    for(cur = __m_uti_head; cur; cur = cur->next) {      \ 
      unit_test_set_run_last_line(__LINE__);      \ 
      if (!unit_test_item_pump_do(this_file_id, cur->f, cur->f_name)) \ 
        return false;          \ 
    }                 \ 
    return true;              \ 
} 

Я получил правильный результат. Я могу вызвать __uti_a_test() и __uti_b_test() по ссылке. Фактически, ссылка __uti_xxx() НЕ реализована с __m_uti_head, поэтому я хочу удалить UTEST_BEGIN() & UTEST_END().

запустить GCC -E переменного тока, макро простираться:

static const bool __m_en = 1; 
static struct __uti *__m_uti_head = ((void *)0); 

static bool __uti_a_test(void); 
__attribute__((constructor)) 
static void uti_construct_a_test(void) 
{ 
    static struct __uti __m_uti_a_test = {((void *)0), file_id_a, __uti_a_test, "a_test" }; 
    utest_item_list_add_global(&__m_uti_a_test); 
} 
static bool __uti_a_test(void) 
{ 
    printf("a test"); 
    return 1; 
} 


bool unit_test_a(void) 
{ 
    if (!__m_en) 
     return 1; 
    struct __uti *cur; 
    for(cur = __m_uti_head; cur; cur = cur->next) { 
     unit_test_set_run_last_line(19); 
     if (!unit_test_item_pump_do(file_id_a, cur->f, cur->f_name)) 
      return 0; 
    } 
    return 1; 
} 

Тест 2:

#define UTEST_BEGIN() 



bool utest_item_list_add_global(struct __uti *uti); 
#define UID(f)               \ 
static bool __uti_##f(void);           \ 
__attribute__((constructor))           \ 
static void uti_construct_##f(void)          \ 
{                  \ 
    printf("%s\n", #f);             \ 
    static struct __uti __m_uti_##f = {NULL, this_file_id, __uti_##f, #f };  \ 
    utest_item_list_add_global(&__m_uti_##f);       \ 
}                  \ 
static bool __uti_##f(void) 


#define UTEST_END(file_name) 

Определение UID() такой же, как в испытании 1. Я держать UTEST_BEGIN() & UTEST_END() как пустое. Компиляция & Ссылка правильная, но uti_construct_a_test() & uti_construct_b_test() НЕ выполняется.

запустить НКУ -E переменного тока, макрос распространяется как:

static bool __uti_a_test(void); 
__attribute__((constructor)) 
static void uti_construct_a_test(void) 
{ 
    static struct __uti __m_uti_a_test = {((void *)0), file_id_a, __uti_a_test, "a_test" }; 
    utest_item_list_add_global(&__m_uti_a_test); 
} 
static bool __uti_a_test(void) 
{ 
    printf("a test"); 
    return 1; 
} 

utest_item_list_add_global() является существование в другом .c файле, функция добавления узла в ссылку:

static struct __uti *m_uti_head = NULL; 
bool utest_item_list_add_global(struct __uti *uti) 
{ 
     if (NULL == m_uti_head) { 
       m_uti_head = uti; 
       return true; 
     } 

     struct __uti *tail = m_uti_head; 
     while (NULL != tail->next) 
       tail = tail->next; 
     tail->next = uti; 
     return true; 
} 

Расширенное макор кажется правильным. Я думаю, проблема в стадии ссылки, я прав?

+0

Ваш код не компилируется. Он также выглядит как рецепт для багги, неподъемного, нечитаемого кода. Не быть отрицательным;). Однако вы могли бы получить некоторое представление о том, что происходит, расширяя макросы, используя, например: 'cpp a.c> a.i'. Посмотрите на дно 'a.i'. Этот файл будет тем, что далее используется для создания кода сборки в процессе компиляции. – Runium

+0

Использование функции GCC __attribute __ ((constructor)), поэтому любая функция, определяемая UID(), может быть связана по ссылке. И пусть пользователь просто думает и записывает тело функции тестирования, не стоит думать, что decalare & вызовет тестовые функции. Всего одна строка. Я чувствую, что это действительно здорово. – husthl

+2

«Действительно круто» * * часто приводит к сложному содержанию кода в долгосрочной перспективе. Изобретение собственного синтаксиса (похоже, что это то, что вы делаете) еще более подвержено этому. Я думаю, @Sukminder имеет очень хороший момент. –

ответ

3

Я нашел GCC атрибут ((конструктор)) есть ниже факта:

cons.c представляет собой файл, который содержит функцию конструктора.

  1. Если в файле cons.c существует только конструктор, скомпилируйте его как статическую библиотеку, а затем свяжите его с main(), конструктор будет игнорировать.
  2. Если какая-либо функция, которая вызывается в main.c, существует в cons.c, скомпилируйте cons.c как статическую библиотеку, а затем свяжите ее с main(), конструктор будет вызываться до main.
  3. Если вы используете «gcc main.c cons.c», конструктор будет вызываться до main.

минусов.C:

#include <stdio.h> 
static void __attribute__((constructor)) construct_fun(void) 
{ 
     printf("this is a constructor\n"); 
} 

void cons(void) 
{ 
     printf("this is cons\n"); 
} 

тест 1:

main.c:

#include <stdio.h> 
int main(void) 
{ 
     printf("this is main\n"); 
} 

компиляции:

gcc -c cons.c 
ar cqs libcon.a cons.o 
gcc main.c libcon.a 

выход: это основная

Тест 2:

main.c:

#include <stdio.h> 
extern void cons(void); 
int main(void) 
{ 
     cons(); 
     printf("this is main\n"); 
} 

компиляции:

gcc -c cons.c 
ar cqs libcon.a cons.o 
gcc main.c libcon.a 

выход:

this is a constructor 
this is cons 
this is main 

Тест 3:

main.c

#include <stdio.h> 
int main(void) 
{ 
     printf("this is main\n"); 
} 

компиляции:

gcc main.c cons.c 

выход:

this is a constructor 
this is main 

запустить "НКУ -v", выход:

Используя встроенные функции , COLLECT_GCC = GCC COLLECT_LTO_WRAPPER =/USR/libexec/GCC/i686-RedHat-Linux/4.7.2/LTO-обертка Цель: i686-RedHat-Linux Сконфигурирован с: ../configure prefix =/USR - -mandir =/usr/share/man --infodir =/usr/share/info --with-bugurl = http://bugzilla.redhat.com/bugzilla --enable-bootstrap --enable-shared --enable-threads = posix --enable-check = release --disable-build-with-cxx --disable-build-poststage1-with-cxx --with-system-zlib --enable -__ cxa_atexit --disable-libunwind-exceptions --enable-gnu-unique-object - enable-linker-build-id --with-linker-hash-style = gnu --enable-languages ​​= c, C++, objc, obj-C++, java, fortran, ada, go, lto --enable-plugin - enable-initfini-array --enable-java-awt = gtk --disable-dssi --with-java-home =/usr/lib/jvm/java-1.5.0-gcj-1.5.0.0/jre --enable -libgcj-multifile --enable-java-maintainer-mode --with-ecj-jar =/usr/share/java/eclipse-ecj.jar --disable-libjava-mu ltilib --with-ppl --with-cloog --with-tune = generic --with-arch = i686 --build = i686-redhat-linux Модель темы: posix gcc version 4.7.2 20121109 (Red Hat 4.7) .2-8) (GCC)

Мой вопрос:

только конструктор существует в файле .c, скомпилировать его как статическая библиотека, почему НКУ игнорировать конструкцию? Как этого избежать?

+0

Когда конструктор находится в объектном файле в статической библиотеке, компоновщик не будет втягивать в этот конструктор если объект не потянут по какой-либо причине. В вашем тесте 2, который происходит, потому что 'main()' вызывает 'cons()', поэтому объектный файл (и конструктор в нем) соединяются. В тесте 1 нет ничего, чтобы заставить компоновщик вытащить объект из библиотека. В тесте 3 объект явно связан, поэтому он включает в себя компоновщик (элементы извлекаются из библиотеки только тогда, когда что-то «запускает» его, иначе вы всегда получите все в библиотеке в каждом исполняемом файле). –

+0

да, [c-linker-issues] (http://stackoverflow.com/questions/1624403/c-linker-issues) описывают тот же вопрос. GCC __attribute __ ((constructor)) приходит после ссылки, может быть ссылка должна учитывать этот вопрос, потому что конструктор отличается от другой функции, у конструктора нет прямого вызывающего. Или я не должен использовать эту область языка C. – husthl