在2个不同版本的gcc上编译源代码

时间:2013-03-05 11:20:47

标签: c gcc

我正在使用不同版本的gcc的两台不同机器上编译我的源代码。

cflags c89

-Wall -Wextra -Wunreachable-code -g -m32 -D_DEBUG -O0 -D_LARGEFILE64_SOURCE -D_REETRANT -D_THREAD_SAFE

一个是redhat-4

gcc (GCC) 4.1.2 20080704 (Red Hat 4.1.2-46)
Linux 203_test_server 2.6.18-164.el5 #1 SMP Tue Aug 18 15:51:48 EDT 2009 x86_64 x86_64 x86_64 GNU/Linux

其中一个是Fedora 18

gcc (GCC) 4.7.2 20121109 (Red Hat 4.7.2-8)
Linux localhost.localdomain 3.8.1-201.fc18.x86_64 #1 SMP Thu Feb 28 19:23:08 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux

我的fedora 18编译没有错误。但是,在redhat 4机器上我遇到了一些错误。

channel.h:35: error: redefinition of typedef ‘channel_t’
internal.h:19: error: previous declaration of ‘channel_t’ was here

我认为错误只是一个循环问题。但是,使用相同的代码库,在2台不同的机器上进行编译真的可以使用2个不同版本的gcc来改变它们吗?

我在考虑使用较新版本的编译器会产生更多错误,因为较新的编译器可能会更严格。

这不是解决错误的问题,而是关于编译器的一般性问题。

我可以设置任何标志以避免将来发生这种情况。也许如果编译这个版本的gcc这样做,如果版本不兼容?

6 个答案:

答案 0 :(得分:11)

这取决于源代码包含哪些标头。如果您要链接到外部库,则可能是您的源代码与旧系统上安装的库版本不兼容。

如果源代码不包含任何外部库头文件(C库除外),则可能存在需要更改的预处理程序指令。

编辑:

Google搜索之后,channel_t似乎来自内核标头。您在两台计算机上使用的内核版本相距甚远。如果代码依赖于内核头文件,则可能需要比Red Hat机器更新的内核版本。您还没有指定代码是什么(它是设备驱动程序吗?),或者它包含的文件,因此很难说更多。

答案 1 :(得分:5)

这与以下内容重复:Why "Redefinition of typedef" error with GCC 4.3 but not GCC 4.6?

答案是更改了gcc以修改此检查。

http://gcc.gnu.org/git/?p=gcc.git;a=commitdiff;h=ce3765bf44e49ef0568a1ad4a0b7f807591d6412

有时,语言中定义的行为警告,但被认为是不良行为,被认为过于严格,因为警告中包含某些有用和/或无害的用例。编译器开发人员然后尝试以相反的方式修复,即减少警告的数量。在这种情况下,只有当第二个定义将typedef更改为不同但兼容的类型时,更改才会显示警告。

其他当前的例子是刚才宣布的gcc 4.8中的-Wshadow。在发行说明中,它表示如果函数名被另一个阴影,-Wshadow将不再发出警告。

请参阅: http://gcc.gnu.org/gcc-4.8/changes.html

编辑:如何避免这种情况:删除其中一个定义,或将其移至单独的包含文件并删除其他定义。

答案 2 :(得分:4)

比较两个系统中channel.h和internal.h的内容,得到不同的结果。我怀疑问题是gcc的版本。错误更有可能是这些文件随着时间的推移而发生代码更改的结果,例如当一个系统具有较新版本的库以及相关的头文件而不是另一个系统时。

答案 3 :(得分:1)

首先,让我们谈谈你的问题。我认为系统在一个系统上出错的最可能原因是代码不一样;您可能希望通过某个工具或diff命令验证这一点,以查找代码库中出现的任何细微更改。 通常,当我看到该错误类型的问题时,您会遇到类似:

typedef struct Foo* Fooptr;

在头文件中然后:

typedef struct Foo
{
    int bar;
} *Fooptr;
源文件中的

。这意味着您可以在源中删除typedef,它应该没问题。只是寻找的东西。

现在,如果 gcc问题,解决问题的第二个选项就是have multiple versions of gcc on the same computer,然后指定{{1}的确切版本通过gcc选项运行。所以在你的Fedora 18机器上给4.1.2拍摄可能是一个好主意。

另外请注意,如果您使用-v选项,但指定要运行的-v版本,您将获得(在stderr输出上)为执行编译阶段而执行的命令。这可能有助于了解正在发生的事情以及每台机器上发生的事情之间是否存在重大差异。


好的,现在回答你的问题。是的,在gcc的“版本X”上有标记用于编译: 对于初学者,有__VERSION__ Predefined Macro,这将向您发回版本号的gcc。这非常有用,但正如gcc文档所述:

  

您不应该依赖具有任何特定形式的内容,但可以指望它至少包含版本号

尽管如此,如果我const char *的{​​{1}}版本为"4.6.3",我通常只看到一种形式的输出,如gcc

现在,如果您知道(或怀疑)某些代码会导致特定版本的4.6.3-1ubuntu5导致错误,您可以使用gcc__GNUC__和{{1预定义的宏到"保护"自己:
这是一个简短的剪辑 - 它在最高级别显示如何使用它:

__GNUC_MINOR__

因此,在版本为4.6.3的上述系统中,您会看到“Hello version 4.x.x”消息。然后你可以获得更高级的功能并检查颠覆:

__GNUC_PATCHLEVEL__

或使用您自己的宏的更干净版本:

#if __GNC__ == 3
    printf(“Hello version 3.x.x\n”);
#elif __GNC__ == 4
    printf(“Hello version 4.x.x\n”);
#endif

要解决有关#if __GNUC__ > 3 || \ (__GNUC__ == 3 && (__GNUC_MINOR__ > 2 || \ (__GNUC_MINOR__ == 2 && \ __GNUC_PATCHLEVEL__ > 0)) printf(“I’m a gcc greater than 3.2.0\n”); #endif 的不同版本是否会产生不同错误的问题,您是正确的,在#define GCC_VERSION (__GNUC__ * 10000 \ + __GNUC_MINOR__ * 100 \ + __GNUC_PATCHLEVEL__) #if GCC_VERSION > 30200 printf(“I’m a gcc greater than 3.2.0\n”); #endif 的每个版本中都会有更多内容发生,有时情况会发生变化,所以您会看到不同版本的编译器之间的差异。最好的办法是检查你所在的两个版本之间的发行说明。 (从4.1到4.7)。

我不确定您的目标架构是什么,因此请务必检查每个文档中的特定部分。但我认为你真的想看一下gccgcc,他们还会制作一个特定于C代码的部分,可以方便地查看。

答案 4 :(得分:1)

这里没有足够的信息来准确说明发生了什么。我和那些说它不太可能是编译器版本问题的人一起加入。

当编译器遇到同一名称的两个不同声明时,显然会发生此错误。要弄清楚为什么会发生这种情况应该不难。

检查makefile以查找被引用的internal.hchannel.h头文件。引用的行将在typedef处有channel_t或其他声明。从这些声明中向外工作以寻找线索。

我必须假设这些文件中的一个或两个都在您正在使用的库中。如果internal.hchannel.h都是您自己的代码,请调试您自己的代码!

否则有很多可能性。最有可能的是

  1. 预处理程序-D#define ed标记不正确,因此只有一个应该是有条件地编译多个声明。

  2. 两个不同的库或标准标题和库都有名称冲突。

  3. 您自己的代码与库或标准标题发生冲突。如果channel_t是您定义的类型,那就是问题所在。您不应该定义以_t结尾的自己的类型,因为这些类型是为实现保留的。

  4. 上面的数字1可以通过多种方式发生,但最常见的是库的配置错误。对于他们正在使用的操作系统,库通常必须./configure。如果您在一个Linux中配置并复制到另一个Linux,则会遇到类似您所看到的问题。

    由于库版本差异,2号可能出现在一个Linux而不是另一个上。在这种情况下,请将带有错误的计算机更新为与没有错误的计算机相同的版本。不要忘记运行./configure

    对于3号,修复是显而易见的。更改您的类型名称。

    我在Tor中看到channel.hchannel_t。我的猜测是你正在使用Tor并在错误的机器上查看Tor配置错误。

答案 5 :(得分:1)

  

这不是解决错误的问题,而是一个普遍的问题   编译器。

     

我可以设置任何标志以避免将来发生这种情况。

编译器的每个特定版本都带有自己的开关或标志。

如果创建编译器版本是为了接受某些开关,而其中一个是您需要避免对源代码进行某些检查的那个,那么是的/将来是一种避免它的方法。

如果你使用的编译器版本,最新版本或未来版本没有/接受开关来避免/跳过对源代码的某些检查,那么就没有办法避免它。