是否有 GCC 编译器/链接器选项来更改 main 的名称? [复制]

Posted

技术标签:

【中文标题】是否有 GCC 编译器/链接器选项来更改 main 的名称? [复制]【英文标题】:is there a GCC compiler/linker option to change the name of main? [duplicate] 【发布时间】:2011-03-07 02:01:55 【问题描述】:

我的软件有一个用于正常使用的 main 和一个用于单元测试的不同的 main。 如果 gcc 有一个选项来指定要使用的“主”函数,我会很高兴的。

【问题讨论】:

这可以通过一次编译器完成吗?即没有“make -D TESTING; make clean; make”?我在交付我测试过的“相同代码”时感到很舒服。 您只需要'-D' 用于包含您的电源的文件。我将有一个构建所有内容的makefile,包括两次主文件(一次使用-D,一次不使用-D ...请注意,它必须使用两个不同的输出文件名进行编译)。然后将它们链接在一起两次:一次用于测试构建,一次用于正常构建。 这个问题早于那个问题,并且有更具体的这个用途的答案。接受的答案是这个问题的更好选择,而不是那个问题的答案。 (而且这两个问题都是古老的)我想取消它们的链接。 【参考方案1】:

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

【讨论】:

另外,OP 仅供参考,只需将 -DTESTING 添加到 gcc 的参数列表中。 最好使用-e作为入口点或strip --strip-symbol @Alex: "你不能删除一个接受的答案" :(【参考方案2】:

编辑:比利比我先回答了,但这里有更多背景

更直接地说,main 通常更多是标准库的一个函数。调用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的主要模块。一个用于单元测试,另一个用于正常使用。

【讨论】:

【参考方案3】:

我假设您正在使用 Make 或类似的东西。我将创建两个包含 main 函数的不同实现的文件,然后在 makefile 中,定义两个单独的目标,它们对其余文件具有相同的依赖关系,除了一个使用您的“单元测试 main”,另一个使用您的“普通 main” ”。像这样的:

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

只要“正常”目标更靠近 makefile 的顶部,然后键入“make”将默认选择它。您必须输入“make unittest”来构建您的测试目标。

【讨论】:

+1:我非常喜欢这种方法,而不是尝试将两个电源塞进同一个主例程中,并在它们之间切换预处理器定义或链接器选项。【参考方案4】:
#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

【讨论】:

唯一的缺点是你需要在define 中包含main 的整个代码...某些IDE 的一些语法着色会使所有测试代码变灰(因为它是通常没有定义),这可能会变得很烦人。【参考方案5】:

您可以使用宏将一个函数重命名为 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[] )  ... 

【讨论】:

【参考方案6】:

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

-e symbol_name

指定主可执行文件的入口点。默认情况下,入口名称为“start”,可在 crt1.o 中找到,其中包含需要设置和调用 main() 的胶水代码。

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

【讨论】:

在 Linux 上:1) 对于 GCC,您还需要 -nostartfiles,否则 crt1.o 中的 main 将未定义并且不会链接 2) 您必须以明确的 @987654329 退出@,否则 return 将无处发生段错误 3) argv 不会为您设置【参考方案7】:

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

【讨论】:

但是main 不是入口点(至少在大多数系统上)。【参考方案8】:

我倾向于使用不同的文件并制作测试和生产版本,但如果你确实有一个文件

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

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

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

【讨论】:

也许值得指出的是,如果您由于某种原因无法重命名生产文件中的 main(就像我的情况一样),您可以在 -D 开关中交换符号名称,即 make它在编译生产主程序时-Dmain=ignored_main【参考方案9】:

首先,您不能在一次编译中拥有两个名为 main 的函数,因此源代码位于不同的文件中,或者您正在使用条件编译。无论哪种方式,您都必须获得两个不同的 .o 文件。因此,您不需要链接器选项;您只需将所需的 .o 文件作为 参数 传递。

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

【讨论】:

【参考方案10】:

如果你使用到LD "-e symbol_name"(当然symbol_name是你的主要功能)你还需要"-nostartfiles"否则会产生"undefined reference to main"的错误。

【讨论】:

我认为这对解决 OP 的问题没有帮助。绕过启动文件会给您留下标准库无法正常工作的破坏环境。我认为只需要-Dmain 和类似的东西。【参考方案11】:

我今天遇到了同样的问题:m1.c 和 m2.c 都有一个 main 函数,但需要链接并运行其中一个。 解决方案:用户 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

【讨论】:

以上是关于是否有 GCC 编译器/链接器选项来更改 main 的名称? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

链接时gcc可以使用多个内核吗?

调试选项 -g 如何更改二进制可执行文件?

如何知道二进制文件是否已与“pie”链接器标志链接?

linux自己写的静态库gcc报错

学习记录:gcc/g++ 编译与链接

CMake add_compile_options 是不是会在适当时影响链接器选项?