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) { /* ... */ }
4
  • 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++. Commented Oct 28, 2015 at 2:43
  • Also try making a C program that includes the header and see if the same errors come up Commented Oct 28, 2015 at 2: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) Commented Oct 28, 2015 at 3: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. watt-32.net/change.log Commented Oct 28, 2015 at 3:20

2 Answers 2

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.

Sign up to request clarification or add additional context in comments.

5 Comments

I just found out about this while digging through the system headers, which use extern __inline__ __attribute__ ((__gnu_inline__)). A comment in <sys/cdefs.h> 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 Thank you!!! As Captain Kirk once said to Scotty: You've earned your pay for the week
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. This codebase is clearly written for gnu89 inline, but being compiled as C99.
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.
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.
0

Perhaps you need include guards?

1 Comment

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..

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.