This question concerns the gcc constructor, the compilation and the link is correct, but it does not start.
There is ac:
UTEST_BEGIN() UID(a_test) { printf("a test"); return true; } UTEST_END(a)
bc is simlar:
UTEST_BEGIN() UID(b_test) { printf("b test"); return true; } UTEST_END(b)
The code object uses UID () to refer to some test functions. My first version adds UTEST_BEGIN () UTEST_END () to enclose UID (), finally I understand that UTEST_BGIN () UTEST_END () is not required, when I change them, I get an unpredictable result.
when I change the definition of UTEST_BEGIN (), UID (), UTEST_END (), I get a different result.
The basic idea is taken from can-i-auto-collect-a-list-of-function-by-c-macro !
Test 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; \ }
I got the correct result. I can call __uti_a_test () and __uti_b_test () by reference. In fact, the __uti_xxx () link is NOT implemented with __m_uti_head, so I want to remove UTEST_BEGIN () and UTEST_END ().
run gcc -E ac, continue the macro as:
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; }
Test 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)
The definition of UID () is similar to definition 1. I keep UTEST_BEGIN () and UTEST_END () empty. The compilation and link are correct, but uti_construct_a_test () and uti_construct_b_test () are NOT executed.
run gcc -E ac, continue the macro as:
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 () exists in another .c file, the function adds node to the link:
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; }
Advanced macros seem right. I think the problem is in the link stage, am I right?