是否有一个GCC编译器/链接器选项来更改main的名称?

我的软件有一个主要用于正常使用,另一个用于unit testing。 如果gcc有一个选项来指定使用哪个“主要”function,我会喜欢它。

将它们放在单独的文件中,并指定一个.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 } 

这里的其他答案是非常合理的,但严格来说,你遇到的问题不是GCC的问题,而是C运行时。 您可以使用-e标志为ld指定程序的入口点。 我的文档说:

-e symbol_name

指定主可执行文件的入口点。 默认情况下,条目名称是“start”,它位于crt1.o中,其中包含需要设置的胶水代码并调用main()。

这意味着您可以根据需要覆盖入口点,但是您可能不希望为要在计算机上正常运行的C程序执行此操作,因为start可能会在程序运行之前执行所需的各种操作系统特定的操作。 如果你可以实现自己的start ,你可以做你想要的。

我假设你正在使用Make或类似的东西。 我将创建两个包含main函数的不同实现的文件,然后在makefile中定义两个独立的目标,这些目标对其余文件具有相同的依赖性,除了一个使用“unit test main”而另一个使用“normal main” ”。 像这样的东西:

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

只要“普通”目标更接近makefile的顶部,那么输入“make”将默认选择它。 您必须输入“make unittest”来构建测试目标。

您可以使用宏将一个函数重命名为main。

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

我倾向于使用不同的文件,并进行测试和生产构建,但如果你确实有一个文件

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

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

那么选择一个或另一个作为主要的编译器选项是-Dtest_main=main-Dprod_main=main

我今天遇到了同样的问题:m1.c和m2.c都有一个主要function,但需要链接并运行其中一个。 解决方案:用户STRIP在编译之后但在链接之前从其中一个中删除主符号:

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

将从m2运行main

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

将从m1运行main

没有条带:

 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 

编辑:比利打败我的答案,但这里有更多的背景

更直接地,main通常更多地是标准库的function。 调用main的东西不是C,而是标准库。 操作系统加载应用程序,将控制权转移到库的入口点(GCC中的_start ),库最终调用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 ,那么写两个只包含main的主模块。 链接一个用于unit testing,另一个用于正常使用。

可能必须单独运行ld才能使用它们,但ld支持脚本来定义输出文件的许多方面(包括入口点)。

首先,在一次编译中不能有两个名为main函数,因此要么源在不同的文件中,要么使用条件编译。 无论哪种方式,你必须得到两个不同的.o文件。 因此,您不需要链接器选项 ; 你只需要传递你想要的.o文件作为参数

如果您不喜欢这样,您可以使用dlopen()从您动态命名的任何目标文件中提取main 。 我可以想象这可能是有用的情况 – 比如,你采用系统的方法进行unit testing,只需将它们全部放在一个目录中,然后你的代码遍历目录,抓取每个目标文件,动态加载它,并运行它的测试。 但要开始,可能需要更简单的东西。

如果您使用LD "-e symbol_name" (其中symbol_name是您的主要function,当然)您还需要"-nostartfiles"否则将产生"undefined reference to main"错误。

 #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给我看了-D和-U