是否有 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 的名称? [复制]的主要内容,如果未能解决你的问题,请参考以下文章