10

I'm trying to use a makefile to compile a program someone else has written, using cygwin. I get a lot of error messages, of which many complain error: template with C linkage.

After searching around for a bit it seems the problem is connected to extern "C". This line is contained in the file cygwin/usr/include/pthread.h, which is included with #include < pthread.h > in one of the headers. And when I remove this line most of the error messages disappear. But there are a few left, of the following sort:

/usr/include/pthread.h:67:5: error: previous declaration of ‘int pthread_atfork(void (*  )(),void ( *)(), void ( *)())’ with ‘C++’ linkage

/usr/include/sys/unistd.h:136:5: error: conflicts with new declaration with ‘C’ linkage

Does anyone know how to fix this? I would love to sit down and learn all this stuff in detail but I don't have time before I need this program running..

shuttle87
  • 15,466
  • 11
  • 77
  • 106
jorgen
  • 3,425
  • 4
  • 31
  • 53
  • 1
    There's not much we can do to help you without seeing the actual code you're trying to compile. – Jim Lewis Aug 28 '13 at 17:47
  • 7
    Do not modify `pthread.h`, that is most probably right, you need to figure out why you get the original error which is most probably not there. First candidate I would look for are macros. – David Rodríguez - dribeas Aug 28 '13 at 17:49

3 Answers3

12

EDIT: Based on the exchange in the comments, the culprit was a header file in the build directory (Endian.h) that conflicted with a system include file /usr/include/endian.h. It was being included instead of the system header, and causing build issues. The files were in conflict because case is insignificant on Windows. The root cause was what was suggested in the original answer. The extern C construct was leaking into C++ code unintentionally, where templates were defined, causing the indicated error.

I would check for a "dangling" C linkage construct in your header files somewhere. This would be in code you wrote (not any of the system headers; those are likely safe).

Code in headers is wrapped with,

on top:

#ifdef __cplusplus
extern "C" {
#endif

and at bottom:

#ifdef __cplusplus
}
#endif

If the bottom part is missing, the effect of the top half extends into code in other headers unintentionally. This causes issues like you are encountering.

Ziffusion
  • 8,779
  • 4
  • 29
  • 57
  • @JonP.Harris The strange thing is, as I mentioned I have not written the code myself and I'm positive it works for other people. I have looked for the code you mention in headers, but cannot find it so far. However I suspect the authors use linux, while I use Windows, and googling around it seems there might be some problem with pthread and cygwin on windows? – jorgen Aug 28 '13 at 18:41
  • 1
    @jorgen What you can do is look at the preprocessed output. Run the compiler command as is, but replace "-c" option with "-E". The output should go into a file specified with "-o" option. Look at it, and if you like, paste file somewhere and post link here (if you want help). – Ziffusion Aug 28 '13 at 19:14
  • Thanks for the suggestion! Problem is, looking at the makefiles I don't understand much of what's going on, and I can't find the file mentioned that includes _pthread.h_ and therefore starts the trouble.. – jorgen Aug 28 '13 at 19:43
  • You can just cut-and-paste the command from the build output into the shell and execute it. The command would be a gcc invocation that should precede the error messages. It should work as long as you are in the right directory. – Ziffusion Aug 28 '13 at 19:46
  • By the way, the last part of the command is " -E -o GarbageFlag.o GarbageFlag.cc ", I assumed it was the .o file you meant – jorgen Aug 28 '13 at 20:20
  • 1
    There seems to be a file named endian.h in the directory that you are compiling in. It is interfering with your build. The compiler is including that file instead of the standard one from /usr/include. – Ziffusion Aug 28 '13 at 20:51
  • Ok! From the looks of it the two files are completely different (by the way the one in my directory is capitalized, as in Endian.h, I guess that doesn't help). I'll try renaming it and changing everywhere it's included. – jorgen Aug 29 '13 at 08:19
  • I renamed the file and it removed the error (although there are others remaining, I'll cut my teeth on those next). Thanks a lot! I guess there is no way to accept a comment as an answer? – jorgen Aug 29 '13 at 11:55
  • 1
    Ah. The capitalization is why it works for other people and not you. On Windows, case is insignificant. I can edit the answer to reflect this exchange. Then you can accept it. – Ziffusion Aug 29 '13 at 14:29
10

This problem arises when your compiler is compiling a mix of C and C++ code. The extern "C" syntax is a way to tell the C++ compiler that a C compiler will also need to access this function. The C compiler doesn't understand this use of extern, so typically you hide it like this:



    #ifdef __cplusplus
    extern "C" {
    #endif
void whatever();
#ifdef __cplusplus } #endif

However, you shouldn't go changing system headers, the chances of those being wrong are very slim. More likely one of your own headers is missing the closing brace above.

sfelber
  • 888
  • 8
  • 23
jhauris
  • 1,153
  • 11
  • 20
3

Similarity to the accepted answer, this was a nesting problem for me as well, but not with ifdef/endif, so I'm adding as a reference for others.

In my case, this error was caused by nested extern "C" constructs; one header file containing an extern "C" construct was included inside another extern "C" construct, causing nesting that confused the compiler/preprocessor.

File a.h:

#ifdef __cplusplus
extern "C"{
#endif

#include "b.h"

#ifdef __cplusplus
}
#endif

File b.h

#ifdef __cplusplus
extern "C"{
#endif

void someFunctionDeclaration();

#ifdef __cplusplus
}
#endif

Moving the #include "b.h" outside of the a.h extern "C" construct fixes the problem.

origo
  • 523
  • 3
  • 6