existe-t-il une option du compilateur / éditeur de liens GCC pour changer le nom de main?

Mon logiciel a un principal pour une utilisation normale et un autre pour les tests unitaires. J’adorerais ça s’il y avait une option à gcc pour spécifier quelle fonction “principale” utiliser.

Placez-les dans des fichiers séparés et spécifiez un fichier .c pour une utilisation normale et un fichier .c pour les tests.

Alternativement, #define testing sur la ligne de commande en utilisant des versions de test et utilise quelque chose comme:

 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 } 

Les autres réponses ici sont tout à fait raisonnables, mais à proprement parler, le problème que vous rencontrez ne concerne pas vraiment GCC, mais plutôt le runtime C. Vous pouvez spécifier un point d’entrée dans votre programme à l’aide de l’indicateur -e to ld . Ma documentation dit:

-e symbol_name

Spécifie le point d’entrée d’un exécutable principal. Par défaut, le nom de l’entrée est “start”, ce qui se trouve dans crt1.o, qui contient le code de collage à configurer et à appeler main ().

Cela signifie que vous pouvez remplacer le point d’entrée si vous le souhaitez, mais vous ne voudrez peut-être pas le faire pour un programme C que vous souhaitez exécuter normalement sur votre ordinateur, car start peut exécuter toutes sortes de tâches spécifiques au système d’exploitation requirejses avant l’exécution de votre programme. Si vous pouvez mettre en œuvre votre propre start , vous pouvez faire ce que vous voulez.

Je suppose que vous utilisez Make ou quelque chose de similaire. Je créerais deux fichiers contenant différentes implémentations de la fonction principale, puis, dans le makefile, définirais deux cibles distinctes ayant des dépendances identiques sur le rest de vos fichiers, sauf que l’un utilise votre “unité de test principale” et l’autre votre “principale normale”. “. Quelque chose comme ça:

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

Tant que la cible “normale” est plus proche du sumt du makefile, taper “make” le choisira par défaut. Vous devrez taper “make unittest” pour construire votre cible de test.

Vous pouvez utiliser des macros pour renommer une fonction en fonction principale.

 #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[] ) { ... } 

J’avais tendance à utiliser des fichiers différents et à réaliser des versions de test et de production, mais si vous aviez un fichier avec

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

et

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

puis les options du compilateur pour sélectionner l’un ou l’autre comme principal sont -Dtest_main=main et -Dprod_main=main

J’ai eu le même problème aujourd’hui: m1.c et m2.c avaient tous deux une fonction principale mais devaient être liés et exécuter l’un d’eux. Solution: l’utilisateur STRIP enlève le symbole principal de l’un d’entre eux après la compilation mais avant la liaison:

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

se déroulera principale de m2

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

se déroulera principale de m1

Sans bande:

 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 

Edit: Billy m’a battu à la réponse, mais voici un peu plus de fond

Plus directement, main est généralement plus une fonction de la bibliothèque standard. La chose qui appelle main n’est pas C, mais la bibliothèque standard. Le système d’exploitation charge l’application, transfère le contrôle sur le point d’entrée de la bibliothèque ( _start dans GCC) et la bibliothèque appelle finalement main . C’est la raison pour laquelle le point d’entrée d’une application Windows peut être WinMain et non l’habitude. La programmation intégrée peut avoir le même genre de chose. Si vous ne disposez pas d’une bibliothèque standard, vous devez écrire le point d’entrée que la bibliothèque fournit normalement (entre autres), et vous pouvez le nommer comme vous le souhaitez.

Dans la chaîne d’outils GCC, vous pouvez également remplacer le point d’entrée de la bibliothèque par le vôtre à l’aide de l’option -e . (D’ailleurs, vous pouvez aussi supprimer complètement la bibliothèque.)


Faire votre propre:

 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 } 

Si vous n’aimez pas ifdef , écrivez deux modules principaux contenant uniquement le principal. Associez-en un pour les tests unitaires et l’autre pour une utilisation normale.

Vous devrez peut- être exécuter ld séparément pour les utiliser, mais ld prend en charge les scripts pour définir de nombreux aspects du fichier de sortie (y compris le point d’entrée).

Tout d’abord, vous ne pouvez pas avoir deux fonctions nommées main dans une compilation. Par conséquent, les sources sont dans des fichiers différents ou vous utilisez une compilation conditionnelle. De toute façon, vous devez sortir deux fichiers .o différents. Par conséquent, vous n’avez pas besoin d’une option de l’ éditeur de liens. vous venez de passer le fichier .o que vous voulez en argument .

Si vous n’aimez pas cela, vous pouvez faire des choses fantaisistes avec dlopen() pour extraire le fichier main d’un fichier object que vous nommez dynamicment. Je peux imaginer des situations où cela pourrait être utile – par exemple, vous adoptez une approche systématique des tests unitaires, vous les mettez tous dans un répertoire et votre code parcourt le répertoire, saisissant chaque fichier object, le chargeant de manière dynamic et exécutant ses tests. Mais pour commencer, quelque chose de plus simple est probablement indiqué.

Si vous utilisez dans LD "-e symbol_name" (où symbol_name est votre fonction principale, bien sûr), vous devez également "-nostartfiles" sinon une erreur de "undefined reference to main" sera produite.

 #ifdef TESTING int main() { /* testing code here */ } #else int main() { /* normal code here */ } #endif 

$ gcc -DTESTING=1 -o a.out filename.c #building for testing

$ gcc -UTESTING -o a.out filename.c #building for normal purposes

man gcc m’a montré le -D et -U