0

I have a C++ program that HAS to use a C based API for a specific task. If I include only in to a single cpp in my program I have no problems at all. However if I include in to a header file (where I need to use some types) I get redefinition errors by the linker.

This is due to a number of typedefs made in the external libraries (C header with compiled dll) header. I am looking for any possible solutions to this problem.

When I search all I can seem to find is header guard stuff (and #pragma once) but these aren't the solution to the problem as what I am finding is multiple definitions in separate compilation units that are then conflicting whilst linking.

I was thinking about extern but found that I am unable to use any types defined in the header as members in a C++ class, which is mostly what I am trying to do.

Output for building on Warning Level 4
Warning 1   warning C4273: 'getwchar' : inconsistent dll linkage    c:\program files (x86)\microsoft visual studio 11.0\vc\include\stdio.h  615 1   project-test
Warning 2   warning C4273: 'putwchar' : inconsistent dll linkage    c:\program files (x86)\microsoft visual studio 11.0\vc\include\stdio.h  617 1   project-test
Warning 3   warning C4273: 'getwchar' : inconsistent dll linkage    c:\program files (x86)\microsoft visual studio 11.0\vc\include\stdio.h  615 1   project-test
Warning 4   warning C4273: 'putwchar' : inconsistent dll linkage    c:\program files (x86)\microsoft visual studio 11.0\vc\include\stdio.h  617 1   project-test
Warning 5   warning C4100: 'data' : unreferenced formal parameter   c:\users\ian\skydrive\documents\uni\finpro\projects\project-test\project-test\main.cpp  8   1   project-test
Warning 6   warning C4100: 'event' : unreferenced formal parameter  c:\users\ian\skydrive\documents\uni\finpro\projects\project-test\project-test\main.cpp  8   1   project-test
Warning 7   warning C4100: 'widget' : unreferenced formal parameter c:\users\ian\skydrive\documents\uni\finpro\projects\project-test\project-test\main.cpp  8   1   project-test
Warning 8   warning C4100: 'data' : unreferenced formal parameter   c:\users\ian\skydrive\documents\uni\finpro\projects\project-test\project-test\main.cpp  15  1   project-test
Warning 9   warning C4100: 'event' : unreferenced formal parameter  c:\users\ian\skydrive\documents\uni\finpro\projects\project-test\project-test\main.cpp  15  1   project-test
Warning 10  warning C4100: 'widget' : unreferenced formal parameter c:\users\ian\skydrive\documents\uni\finpro\projects\project-test\project-test\main.cpp  15  1   project-test
Warning 11  warning C4505: 'g_bit_nth_lsf' : unreferenced local function has been removed   c:\users\ian\skydrive\documents\uni\finpro\gtk\include\glib-2.0\glib\gutils.h   267 1   project-test
Warning 12  warning C4505: 'g_bit_nth_msf' : unreferenced local function has been removed   c:\users\ian\skydrive\documents\uni\finpro\gtk\include\glib-2.0\glib\gutils.h   269 1   project-test
Warning 13  warning C4505: 'g_bit_storage' : unreferenced local function has been removed   c:\users\ian\skydrive\documents\uni\finpro\gtk\include\glib-2.0\glib\gutils.h   271 1   project-test
Warning 14  warning C4505: 'g_string_append_c_inline' : unreferenced local function has been removed    c:\users\ian\skydrive\documents\uni\finpro\gtk\include\glib-2.0\glib\gstring.h  130 1   project-test
Warning 15  warning C4505: 'g_trash_stack_push' : unreferenced local function has been removed  c:\users\ian\skydrive\documents\uni\finpro\gtk\include\glib-2.0\glib\gtrashstack.h  44  1   project-test
Warning 16  warning C4505: 'g_trash_stack_pop' : unreferenced local function has been removed   c:\users\ian\skydrive\documents\uni\finpro\gtk\include\glib-2.0\glib\gtrashstack.h  46  1   project-test
Warning 17  warning C4505: 'g_trash_stack_peek' : unreferenced local function has been removed  c:\users\ian\skydrive\documents\uni\finpro\gtk\include\glib-2.0\glib\gtrashstack.h  47  1   project-test
Warning 18  warning C4505: 'g_trash_stack_height' : unreferenced local function has been removed    c:\users\ian\skydrive\documents\uni\finpro\gtk\include\glib-2.0\glib\gtrashstack.h  48  1   project-test
Error   19  error LNK2005: "long __cdecl abs(long)" (?abs@@YAJJ@Z) already defined in FitsFile.obj  C:\Users\Ian\SkyDrive\Documents\Uni\FINPRO\projects\project-test\project-test\main.obj  project-test
Error   20  error LNK2005: "__int64 __cdecl abs(__int64)" (?abs@@YA_J_J@Z) already defined in FitsFile.obj  C:\Users\Ian\SkyDrive\Documents\Uni\FINPRO\projects\project-test\project-test\main.obj  project-test
Error   21  error LNK2005: "struct _ldiv_t __cdecl div(long,long)" (?div@@YA?AU_ldiv_t@@JJ@Z) already defined in FitsFile.obj   C:\Users\Ian\SkyDrive\Documents\Uni\FINPRO\projects\project-test\project-test\main.obj  project-test
Error   22  error LNK2005: "struct _lldiv_t __cdecl div(__int64,__int64)" (?div@@YA?AU_lldiv_t@@_J0@Z) already defined in FitsFile.obj  C:\Users\Ian\SkyDrive\Documents\Uni\FINPRO\projects\project-test\project-test\main.obj  project-test
Error   23  error LNK2005: _getwchar already defined in FitsFile.obj    C:\Users\Ian\SkyDrive\Documents\Uni\FINPRO\projects\project-test\project-test\main.obj  project-test
Error   24  error LNK2005: _putwchar already defined in FitsFile.obj    C:\Users\Ian\SkyDrive\Documents\Uni\FINPRO\projects\project-test\project-test\main.obj  project-test
Error   25  error LNK1169: one or more multiply defined symbols found   C:\Users\Ian\SkyDrive\Documents\Uni\FINPRO\projects\project-test\Debug\project-test.exe project-test

output on warning level 4

Output for building on Warning Level 4 (when only including for one place)
Warning 1   warning C4273: 'getwchar' : inconsistent dll linkage    c:\program files (x86)\microsoft visual studio 11.0\vc\include\stdio.h  615 1   project-test
Warning 2   warning C4273: 'putwchar' : inconsistent dll linkage    c:\program files (x86)\microsoft visual studio 11.0\vc\include\stdio.h  617 1   project-test
Warning 3   warning C4100: 'data' : unreferenced formal parameter   c:\users\ian\skydrive\documents\uni\finpro\projects\project-test\project-test\main.cpp  8   1   project-test
Warning 4   warning C4100: 'event' : unreferenced formal parameter  c:\users\ian\skydrive\documents\uni\finpro\projects\project-test\project-test\main.cpp  8   1   project-test
Warning 5   warning C4100: 'widget' : unreferenced formal parameter c:\users\ian\skydrive\documents\uni\finpro\projects\project-test\project-test\main.cpp  8   1   project-test
Warning 6   warning C4100: 'data' : unreferenced formal parameter   c:\users\ian\skydrive\documents\uni\finpro\projects\project-test\project-test\main.cpp  15  1   project-test
Warning 7   warning C4100: 'event' : unreferenced formal parameter  c:\users\ian\skydrive\documents\uni\finpro\projects\project-test\project-test\main.cpp  15  1   project-test
Warning 8   warning C4100: 'widget' : unreferenced formal parameter c:\users\ian\skydrive\documents\uni\finpro\projects\project-test\project-test\main.cpp  15  1   project-test
Warning 9   warning C4505: 'g_bit_nth_lsf' : unreferenced local function has been removed   c:\users\ian\skydrive\documents\uni\finpro\gtk\include\glib-2.0\glib\gutils.h   267 1   project-test
Warning 10  warning C4505: 'g_bit_nth_msf' : unreferenced local function has been removed   c:\users\ian\skydrive\documents\uni\finpro\gtk\include\glib-2.0\glib\gutils.h   269 1   project-test
Warning 11  warning C4505: 'g_bit_storage' : unreferenced local function has been removed   c:\users\ian\skydrive\documents\uni\finpro\gtk\include\glib-2.0\glib\gutils.h   271 1   project-test
Warning 12  warning C4505: 'g_string_append_c_inline' : unreferenced local function has been removed    c:\users\ian\skydrive\documents\uni\finpro\gtk\include\glib-2.0\glib\gstring.h  130 1   project-test
Warning 13  warning C4505: 'g_trash_stack_push' : unreferenced local function has been removed  c:\users\ian\skydrive\documents\uni\finpro\gtk\include\glib-2.0\glib\gtrashstack.h  44  1   project-test
Warning 14  warning C4505: 'g_trash_stack_pop' : unreferenced local function has been removed   c:\users\ian\skydrive\documents\uni\finpro\gtk\include\glib-2.0\glib\gtrashstack.h  46  1   project-test
Warning 15  warning C4505: 'g_trash_stack_peek' : unreferenced local function has been removed  c:\users\ian\skydrive\documents\uni\finpro\gtk\include\glib-2.0\glib\gtrashstack.h  47  1   project-test
Warning 16  warning C4505: 'g_trash_stack_height' : unreferenced local function has been removed    c:\users\ian\skydrive\documents\uni\finpro\gtk\include\glib-2.0\glib\gtrashstack.h  48  1   project-test

enter image description here

Ian Cant
  • 403
  • 3
  • 11
  • 4
    It sounds like this C "API" is not very API-like if you have this much trouble with using. Are there detailed instructions or anything on usage? – crashmstr Nov 26 '13 at 15:46
  • 3
    typedefs are only a problem if the file is included twice for the same object file. redefintion in the linker phase is due to definition of variables - so you need to provide more info on the header and the exact errors – mmmmmm Nov 26 '13 at 15:48
  • Can you clarify if the linker is complaining about duplicate functions or duplicate variables? – Will Dean Nov 26 '13 at 15:54
  • The issue is with typedefs: error LNK2005: "struct _ldiv_t __cdecl div(long,long)" (?div@@YA?AU_ldiv_t@@JJ@Z) already defined in FitsFile.obj – Ian Cant Nov 26 '13 at 15:58
  • 1
    Really the *whole* point of include files is to include them multiple times. If your include files are written in such a way that this causes problem then you need to fix the include files, not ask how do I include a file only once. – john Nov 26 '13 at 15:58
  • 2
    @IanCant That's not a typedef issue. It's a multiply defined function. – john Nov 26 '13 at 15:59
  • The problem is that you set up your project wrongly so that you get multiple definitions of functions. Since you've said very little about how you've set up your project it's hard to help. – john Nov 26 '13 at 16:00
  • @john The functions in the header do not give a problem (as they are only prototypes). Here is one of the problem cases: #if (_MSC_VER < 1300) /* versions earlier than V7.0 do not have 'long long' */ typedef __int64 LONGLONG; #else /* newer versions do support 'long long' */ typedef long long LONGLONG; #endif – Ian Cant Nov 26 '13 at 16:02
  • @IanCant - That error you just posted is about a function called 'div', not a typedef. – Will Dean Nov 26 '13 at 16:05
  • @IanCant So you have a bugged header file written by a third party, is that what you are saying? I think this is going to be hard to sort out in this forum, unless by chance you find someone who has faced the same problem. – john Nov 26 '13 at 16:07
  • @WillDean The error is regarding a struct. Note this is a linker error not a compiler error. – Ian Cant Nov 26 '13 at 16:08
  • @IanCant - It's not, it's about a function called 'div' which returns a struct - the linker doesn't know anything about typedefs. – Will Dean Nov 26 '13 at 16:09
  • @WillDean I guessing, but I think the point is that there are typedefs which cause functions whose definitions should be different to acutally be identical. Hence multiple definition errors, presumably div is one such function. – john Nov 26 '13 at 16:12
  • @john Oh yes, maybe - good point. Perhaps they've got `typedef int long` in there... – Will Dean Nov 26 '13 at 16:13
  • @john sorry my mistake can see its a function now. Had hell on this all day. – Ian Cant Nov 26 '13 at 16:16
  • @WillDean ditto. I can make limited modifications to the header but cannot find a reference to a div or abs function in there. The files include a load of other stuff – Ian Cant Nov 26 '13 at 16:17
  • @IanCant `div` and `abs` are standard functions defined in `` – john Nov 26 '13 at 16:20
  • @IanCant - I think john is on to something here, that something in that header file has polluted the standard types to such an extent that it's made different functions collapse on to each other. Are you compiling at warning level 4? I would expect you'd be seeing a bunch of compiler warnings which would be an early warning of what's going to go wrong at link time. – Will Dean Nov 26 '13 at 16:25
  • @WillDean I have modified the question to include the 18 warnings and 7 errors I am getting. – Ian Cant Nov 26 '13 at 16:29
  • @IanCant Please post text version, those images aren't readable for me at least. – dutt Nov 26 '13 at 16:38
  • @dutt I have added them in. Thanks for all your help with this :) – Ian Cant Nov 26 '13 at 16:43
  • The warnings are all from the use of GTK3 (or at least from what I can tell) as they are all in the glib-2.0 folder. With the exception of the unreferenced local parameter ones. But this reference variables used in the GTK section of my program. – Ian Cant Nov 26 '13 at 16:45

3 Answers3

2

Abstract the C functionality behind a layer of indirection:

original structure (if I understand correctly this is what you have now):

file1.h -> #include included_c_api.h
file2.h -> #include included_c_api.h CAUSES errors.

new structure:

new_c_api.h -> wrapper over included_c_api.h functionality (w/ your own symbols)
new_c_api.c[pp] -> #include included_c_api.h
file1.h -> #include new_c_api.h
file2.h -> #include new_c_api.h

If the functionality exposed in included_c_api.h is very big, this solution could be impractical.

utnapistim
  • 26,809
  • 3
  • 46
  • 82
  • As far as I can tell from my digging and the above comments, this seems the only real solution I have available. It ensures the file is only included once behind a layer of indirection. – Ian Cant Nov 26 '13 at 23:24
  • Thus removes the errors from compiler and ensures it can be used. See comments on question for further explanation. – Ian Cant Nov 26 '13 at 23:30
0

Look for two things:

a) You don't use include guards. As a general rule, all your headers should have the following structure. This ensures that only a single copy of a header is included into a C++ file.

#ifndef MYPROJECT_DIR_FILE_H
#define MYPROJECT_DIR_FILE_H

... all declarations and definitions ...

#endif

b) Make sure all functions that are defined in a header are inline. Otherwise, multiple C++ files will have copies of the same function which will confuse the linker. inline requests to discard all except one copies of the function.

p12
  • 1,161
  • 8
  • 23
  • `inline` doesn't request discarding, it causes the function to be embedded into that object module's own code, so that the linker doesn't see it at all. – Will Dean Nov 26 '13 at 15:53
  • Not true: `inline` functions can still be odr-used which causes a regular definition to be included. In any case, the compiler is free to ignore `inline` anyway. – p12 Nov 26 '13 at 15:55
0

You don't say if the problem is with variables or functions. They have different solutions:

variables: the header file must have an 'extern' declaration for a variable, with just one 'C' file containing a definition (same as the extern declaration, but without the word extern in front).

functions: this only happens when you have function bodies in the headers - in which case you should put 'inline' in front of the function definition, so that the function code is embedded into each object module which uses it, and the linker doesn't have to deal with it at all. Function prototypes will not cause duplicate definition errors.

When linking C code and C++ code, you also need to get the name mangling right - which basically means you should surround all the declarations which apply to 'C' objects with the following code when you compile those declarations with a C++ compiler:

extern "C" { 

... 'C' declarations

}

You usually see

#if defined(__cplusplus)
extern "C" { 
#endif 

at the top of header files (an similar code at the bottom) which have been designed to be included in both C and C++ files. This is well covered here - but it doesn't sound like you currently have a name mangling problem, though I expect you will before the project's finished...

Community
  • 1
  • 1
Will Dean
  • 39,055
  • 11
  • 90
  • 118