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

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

【问题讨论】:

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

标签: c gcc main entry-point


【解决方案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
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2021-07-29
          • 2016-09-13
          • 1970-01-01
          • 1970-01-01
          • 2013-11-12
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多