4

I'm trying to use a library (Watt-32, if it's relevant), which fails to link for some reason. I've compiled the library and as a quick "hello world" test, I'm trying to compile the following file:

#include <tcp.h>
int main() { sock_init(); } 

This causes GCC to produce a long list of multiple definition errors, in the library's own source files:

D:\projects\test-tcp>c++ -Iinclude test-tcp.cpp -Llib -lwatt

lib\libwatt.a(rs232.o): In function `_ntohl':
D:\msys64\home\JW\watt32\src/../inc/sys/swap.h:63: multiple definition of `__ntohl'
lib\libwatt.a(pctcp.o):D:\msys64\home\JW\watt32\src/../inc/sys/swap.h:63: first defined here
lib\libwatt.a(rs232.o): In function `_ntohs':
D:\msys64\home\JW\watt32\src/../inc/sys/swap.h:73: multiple definition of `__ntohs'
lib\libwatt.a(pctcp.o):D:\msys64\home\JW\watt32\src/../inc/sys/swap.h:73: first defined here
lib\libwatt.a(rs232.o): In function `get_fs_reg':
D:\msys64\home\JW\watt32\src/misc.h:736: multiple definition of `get_fs_reg'
lib\libwatt.a(pctcp.o):D:\msys64\home\JW\watt32\src/misc.h:736: first defined here
lib\libwatt.a(rs232.o): In function `get_gs_reg':
D:\msys64\home\JW\watt32\src/misc.h:744: multiple definition of `get_gs_reg'
lib\libwatt.a(pctcp.o):D:\msys64\home\JW\watt32\src/misc.h:744: first defined here
lib\libwatt.a(rs232.o): In function `set_fs_reg':
D:\msys64\home\JW\watt32\src/misc.h:751: multiple definition of `set_fs_reg'
lib\libwatt.a(pctcp.o):D:\msys64\home\JW\watt32\src/misc.h:751: first defined here
lib\libwatt.a(rs232.o): In function `set_gs_reg':
D:\msys64\home\JW\watt32\src/misc.h:757: multiple definition of `set_gs_reg'
lib\libwatt.a(pctcp.o):D:\msys64\home\JW\watt32\src/misc.h:757: first defined here
lib\libwatt.a(ports.o): In function `_ntohl':
D:\msys64\home\JW\watt32\src/../inc/sys/swap.h:63: multiple definition of `__ntohl'
lib\libwatt.a(pctcp.o):D:\msys64\home\JW\watt32\src/../inc/sys/swap.h:63: first defined here
lib\libwatt.a(ports.o): In function `_ntohs':
D:\msys64\home\JW\watt32\src/../inc/sys/swap.h:73: multiple definition of `__ntohs'
lib\libwatt.a(pctcp.o):D:\msys64\home\JW\watt32\src/../inc/sys/swap.h:73: first defined here
lib\libwatt.a(ports.o): In function `get_fs_reg':
D:\msys64\home\JW\watt32\src/misc.h:736: multiple definition of `get_fs_reg'
lib\libwatt.a(pctcp.o):D:\msys64\home\JW\watt32\src/misc.h:736: first defined here
lib\libwatt.a(ports.o): In function `get_gs_reg':
D:\msys64\home\JW\watt32\src/misc.h:744: multiple definition of `get_gs_reg'
lib\libwatt.a(pctcp.o):D:\msys64\home\JW\watt32\src/misc.h:744: first defined here
lib\libwatt.a(ports.o): In function `set_fs_reg':
D:\msys64\home\JW\watt32\src/misc.h:751: multiple definition of `set_fs_reg'
lib\libwatt.a(pctcp.o):D:\msys64\home\JW\watt32\src/misc.h:751: first defined here
lib\libwatt.a(ports.o): In function `set_gs_reg':
D:\msys64\home\JW\watt32\src/misc.h:757: multiple definition of `set_gs_reg'
lib\libwatt.a(pctcp.o):D:\msys64\home\JW\watt32\src/misc.h:757: first defined here
lib\libwatt.a(language.o): In function `_ntohl':
[... etc ...]

I must be doing something wrong here, but what exactly? It seems like a problem with the library itself..?

edit: These functions are defined as follows in the library source: (implementation omitted, it's all inline assembly code)

extern __inline__ WORD get_fs_reg (void)     { /* ... */ }
extern __inline__ WORD get_gs_reg (void)     { /* ... */ }
extern __inline__ void set_fs_reg (WORD sel) { /* ... */ }
extern __inline__ void set_gs_reg (WORD sel) { /* ... */ }
/*@unused@*/ extern __inline__ unsigned long __ntohl (unsigned long x)  { /* ... */ }
/*@unused@*/ extern __inline__ unsigned short __ntohs (unsigned short x) { /* ... */ }
user5434231
  • 579
  • 3
  • 16
  • The problem could be with function definitions in header files. Have a look at the code where `get_fs_reg` and `get_gs_reg` are defined, in `misc.h` (post that code in the question perhaps). Maybe they are not marked as `inline` when they should be. Also, C and C++ behave differently w.r.t. inline functions. so if this library was a C library it's possible that the headers may need some change to be usable from C++. – M.M Oct 28 '15 at 02:43
  • Also try making a C program that includes the header and see if the same errors come up – M.M Oct 28 '15 at 02:44
  • @M.M, all these functions are actually marked `__inline__`, and compiled with -O2. I've added their definitions to the question. Compiling the test file as plain C doesn't make any difference. (which I guess makes the c++ tag somewhat irrelevant) – user5434231 Oct 28 '15 at 03:18
  • See if there is a newer version of the library and headers. The changelog mentions "misc.h change: Watcom uses 'i64' suffix for 64-bit values.". I wonder if both 32 bit and 64 bit functions are somehow being compiled into the same library. http://www.watt-32.net/change.log – Sammy Oct 28 '15 at 03:20

2 Answers2

5

These header files are a bit old/dated. The usage of extern inline has changed with newer compilers. extern inline was the preferred way for many years. It worked fine on gcc but clang needed static inline

Now, even gcc wants static inline even with -O2 or you get what you're seeing. Since you're recompiling from source, you may have to edit the .h and change all of them to static.

I have boilerplate for my code that was #define craigs_inline extern inline and now I've switched it to #define craigs_inline static inline to keep the peace.

Note that I didn't investigate a compiler -foption_whatever that might obviate the need for this. If you find you one, please send me a comment as I'd be interested to know.

Craig Estey
  • 30,627
  • 4
  • 24
  • 48
  • 1
    I *just* found out about this while digging through the system headers, which use `extern __inline__ __attribute__ ((__gnu_inline__))`. A comment in `` notes that this attribute is equivalent to compiling with `-fgnu89-inline`. And yes, after recompiling the Watt32 library with this option, my test file also compiles without errors! :) – user5434231 Oct 28 '15 at 05:15
  • @user5434231 Thank _you_!!! As Captain Kirk once said to Scotty: _You've earned your pay for the week_ – Craig Estey Oct 28 '15 at 05:22
  • More info: In C, there was officially no `inline` before C99. GCC rolled their own ; and C99 inline has different behaviour for the same code than gnu89. A mess. C++ is different again. [Summary here](http://stackoverflow.com/questions/216510/extern-inline/216546#216546). This codebase is clearly written for gnu89 inline, but being compiled as C99. – M.M Oct 28 '15 at 21:10
  • My advice for portable code would be to not use inline functions in headers which are to be included from both C and C++ ; however in practice I think you would get away with using `static inline` in all dialects. – M.M Oct 28 '15 at 21:11
  • Yes, it's a mess. My code does #ifdef's on CLANG, OPTIMIZE cplusplus GNUC etc, and defines abstract macros as mentioned in my answer. There is one [and only one place] that it does this and _every_ other .h file uses the abstracts. This has and does work. So, not a mess. For a new situation, I add new #ifdef's [and/or simplify]. The abstracts could be def'ed by autoconf, etc. BTW, I defined the abstracts on the very first day I wrote an inline [~20 years ago] because I saw the problem up front. Not unique, others do INLINE similarly. – Craig Estey Oct 28 '15 at 22:00
0

Perhaps you need include guards?

mentat
  • 2,748
  • 1
  • 21
  • 40
  • It looks like a linker error to me. Perhaps compile with gcc -c first to compile only - that should prove it is the library linking that is failing.. – Sammy Oct 28 '15 at 03:07