есть ли опция компилятора / компоновщика GCC для изменения имени main? - PullRequest
15 голосов
/ 23 июня 2010

Мое программное обеспечение имеет одну основную для обычного использования и другую для модульных тестов. Мне бы очень понравилось, если бы в gcc была возможность указать, какую «основную» функцию использовать.

Ответы [ 11 ]

14 голосов
/ 23 июня 2010

Другие ответы здесь вполне разумны, но, строго говоря, проблема, с которой вы столкнулись, заключается не в GCC, а в среде выполнения C.Вы можете указать точку входа в вашу программу, используя флаг -e для ld.Моя документация гласит:

-e symbol_name

Определяет точку входа основного исполняемого файла.По умолчанию имя записи «start», которое находится в crt1.o и содержит клейкий код, который необходимо установить и вызвать main ().

Это означает, что вы можете переопределить точку входа, если выкак, но вы можете не захотеть делать это для программы на C, которую вы собираетесь нормально запускать на своей машине, поскольку start может выполнять все виды специфических для ОС вещей, которые требуются до запуска вашей программы.Если вы можете реализовать свой собственный start, вы можете делать то, что вы хотите.

8 голосов
/ 23 июня 2010

Поместите их в отдельные файлы и укажите один файл .c для обычного использования и один файл .c для тестирования.

Альтернативно #define тестирование в командной строке с использованием тестовых сборок и использование чего-то вроде:

int main(int argc, char *argv[])
{
#ifdef TESTING
    return TestMain(argc, argv);
#else
    return NormalMain(argc, argv);
#endif
}

int TestMain(int argc, char *argv[])
{
    // Do testing in here
}

int NormalMain(int argc, char *argv[])
{
    //Do normal stuff in here
}
7 голосов
/ 23 июня 2010

Вы можете использовать макросы для переименования одной функции в основную.

#ifdef TESTING
#define test_main main
#else
#define real_main main
#endif

int test_main( int argc, char *argv[] ) { ... }
int real_main( int argc, char *argv[] ) { ... }
7 голосов
/ 23 июня 2010

Я предполагаю, что вы используете Make или что-то подобное. Я хотел бы создать два файла, которые содержат разные реализации основной функции, затем в make-файле определить две отдельные цели, которые имеют идентичные зависимости от остальных ваших файлов, за исключением того, что один использует ваш «основной тестовый модуль», а другой - ваш «обычный основной». ». Примерно так:

normal: main_normal.c file1.c file2.c
unittest: main_unittest.c file1.c file2.c

Пока «нормальная» цель находится ближе к вершине файла makefile, то по умолчанию будет набирать «make». Вам нужно будет набрать «make unittest», чтобы построить тестовую цель.

6 голосов
/ 23 июня 2010

Я бы обычно использовал разные файлы и создавал их для тестирования и производственных сборок, но если у вас был файл с

int test_main (int argc, char*argv[])

и

int prod_main (int argc, char*argv[])

, тогда параметры компиляторадля выбора одного или другого в качестве основных -Dtest_main=main и -Dprod_main=main

5 голосов
/ 20 декабря 2012

У меня сегодня была одна и та же проблема: m1.c и m2.c оба имели основную функцию, но их нужно было связать и запустить одну из них.Решение: пользователь STRIP удалит главный символ из одного из них после компиляции, но перед компоновкой:

gcc -c m1.c m2.c;  strip --strip-symbol main m1.o; gcc m1.o m2.o; ./a.out

запустит main из m2

gcc -c m1.c m2.c;  strip --strip-symbol main m2.o; gcc m1.o m2.o; ./a.out

запустит main из m1

без полоски:

gcc - m1.c m2.c
m2.o: In function `main':
m2.c:(.text+0x0): multiple definition of `main'
m1.o:m1.c:(.text+0x0): first defined here
collect2: ld returned 1 exit status
2 голосов
/ 23 июня 2010

Редактировать: Билли опередил меня с ответом, но вот еще немного фона

Более конкретно, main обычно больше зависит от стандартной библиотеки. То, что вызывает main, это не C, а стандартная библиотека. ОС загружает приложение, передает управление в точку входа библиотеки (_start в GCC), и в конечном итоге библиотека вызывает main. Вот почему точка входа для приложения Windows может быть WinMain, а не обычной. Встроенное программирование может иметь то же самое. Если у вас нет стандартной библиотеки, вам нужно написать точку входа, которую обычно предоставляет библиотека (помимо прочего), и вы можете назвать ее как угодно.

В наборе инструментов GCC вы также можете заменить точку входа библиотеки своей собственной, используя опцию -e. (В этом отношении вы также можете полностью удалить библиотеку.)


Сделай свой собственный:

int main(int argc, char *argv[])
{
#if defined(BUILD_UNIT_TESTS)
    return main_unittest(argc, argv);
#endif
#if defined(BUILD_RUNTIME)
    return main_run(argc, argv);
#endif
}

Если вам не нравится ifdef, напишите два основных модуля, которые содержат только основной. Соедините одно для модульных тестов, а другое - для обычного использования.

0 голосов
/ 01 октября 2012

Если вы используете в LD "-e symbol_name" (где symbol_name - ваша основная функция, конечно), вам также нужно "-nostartfiles", иначе будет выдано сообщение об ошибке "undefined reference to main".

0 голосов
/ 23 июня 2010

Прежде всего, вы не можете иметь две функции с именем main в одной компиляции, поэтому либо источники находятся в разных файлах, либо вы используете условную компиляцию.В любом случае вы должны получить два разных .o файла.Следовательно, вам не нужен компоновщик option ;Вы просто передаете нужный файл .o в качестве аргумента .

Если вам это не нравится, вы можете сделать что-то необычное с помощью dlopen(), чтобы вытащить main излюбой объектный файл, который вы называете динамически.Я могу себе представить обстоятельства, когда это может быть полезно - скажем, вы применяете системный подход к модульным тестам, просто помещаете их все в каталог, и ваш код обходит каталог, захватывает каждый объектный файл, динамически загружает его и запускает его тесты.Но для начала, вероятно, указывается что-то более простое.

0 голосов
/ 23 июня 2010

Вы возможно должны запускать ld отдельно для их использования, но ld поддерживает сценарии для определения многих аспектов выходного файла (включая точку входа).

...