1

I'm trying to compile grpc, and one of the targets uses /usr/include/netinet/tcp.h which contains this :

# if __BYTE_ORDER == __LITTLE_ENDIAN
        uint8_t th_x2:4;        /* (unused) */
        uint8_t th_off:4;       /* data offset */
# endif
# if __BYTE_ORDER == __BIG_ENDIAN
        uint8_t th_off:4;       /* data offset */
        uint8_t th_x2:4;        /* (unused) */
# endif

Somehow, the two conditions are fulfilled which makes the compilation fail (error: duplicate member 'th_off'). I wrote a test C program and it seems that the three macros are not correctly defined.

I tried to reinstall gcc and g++, and also downgrade them to a previous version. I also tried to reinstall the Linux headers. I finally tried to compile with clang, but it doesn't work either.

My two test computers are running Ubuntu 19.10 and the result is the same on both of them. Is there a compiler flag or a system configuration needed to define these macros?

EDIT : tcp.h is a system header. I did not write it and it's an almost fresh install of Ubuntu with a standard installation of build-essentials.

EDIT 2 : I used a test program and it works correctly in this case. It shows little:

#include <iostream>
#include <netinet/tcp.h>

int main() {
#if __BYTE_ORDER == __LITTLE_ENDIAN
    std::cout << "little\n";
#endif
#if __BYTE_ORDER == __BIG_ENDIAN
    std::cout << "big\n";
#endif
}
Ted Lyngmo
  • 93,841
  • 5
  • 60
  • 108
loics2
  • 616
  • 1
  • 10
  • 24
  • `__LITTLE_ENDIAN` and `__BIG_ENDIAN` are two different constants, so they can't both be equal. Somewhere in the source they have been redefined. – stark Feb 19 '20 at 20:56
  • 1
    @stark He's saying they're not defined at all, so the preprocessor is treating them all as `0`. – Barmar Feb 19 '20 at 20:57
  • What do you get if you `printf("BE: %d\nLE: %d\nBO: %d\n", __BIG_ENDIAN, __LITTLE_ENDIAN, __BYTE_ORDER)` – Christian Gibbons Feb 19 '20 at 20:58
  • I see these two constants in /usr/include/endian.h – stark Feb 19 '20 at 20:58
  • 1
    @stark I see them defined in `/usr/include/endian.h`. `bits/endian.h` just defines `__BYTE_ORDER` to one of them. – Barmar Feb 19 '20 at 21:01
  • Yeah - I was looking on Cygwin. On Ubuntu they're in /usr/include/endian.h – stark Feb 19 '20 at 21:02
  • Please add your test program to your question. – Nate Eldredge Feb 19 '20 at 21:08
  • In which source file of `grpc` is this happening? – user3684240 Feb 19 '20 at 21:16
  • You can of course simply define the macros appropriately in your makefile or even on top of your includes in the sources, potentially evaluating the other possibilities as well. Admittedly that is very unsatisfying. There is also a [header file online](https://github.com/torvalds/linux/blob/master/include/uapi/linux/tcp.h) which says "#error "Adjust your defines" if the expected defines aren't there, indicating that this is not uncommon. – Peter - Reinstate Monica Feb 19 '20 at 21:17
  • @user3684240 grpc/src/core/lib/iomgr/socket_utils_common_posix.cc – loics2 Feb 19 '20 at 21:21
  • And the system header code you post is leaving me wanting from a code quality standpoint. One should test for #ifdef, and if that seems to cumbesome, one can always use [function-like macros](https://stackoverflow.com/a/33760158/3150802) which don't compile if undefined, instead of silently and wrongly resolving to 0. – Peter - Reinstate Monica Feb 19 '20 at 21:27
  • 1
    I added the test program result in my question – loics2 Feb 19 '20 at 21:33
  • Perhaps you are using a different compiler than the one whose system headers are not in `/usr/include` ? It would be rather poor if this grpc explicitly lists that parth to include. – M.M Feb 19 '20 at 21:37
  • Re "*I used a test program and it works correctly in this case.*", Please provide the minimal case where it *doesn't* work. – ikegami Feb 19 '20 at 21:40
  • @ikegami The problem with `grpc` is that it's a massive project. It may be hard to figure out how to create a mcve. I just compiled it and was sort of hoping to get the same problem - but all compiled just fine. – Ted Lyngmo Feb 19 '20 at 21:44
  • @loics2 When you built, did you add any configuration or did you just do `mkdir build; cd build; cmake ..; make`? – Ted Lyngmo Feb 19 '20 at 21:48
  • @Ted Lyngmo Re "*The problem with grpc is that it's a massive project.*", Right, and the OP didn't identify the steps they took; they didn't pare down the program to a compilation unit; nothing. "I'm trying to compile grpc" is not a suitable demonstration of a problem, *especially* for something as large as this. – ikegami Feb 19 '20 at 21:53
  • @ikegami Perhaps not. The file `grpc/src/core/lib/iomgr/socket_utils_common_posix.cc` was mentioned, but only in a comment. – Ted Lyngmo Feb 19 '20 at 21:55
  • @TedLyngmo yep, just that – loics2 Feb 19 '20 at 21:55

2 Answers2

1

On my Debian system, __LITTLE_ENDIAN and __BIG_ENDIAN are defined in /usr/include/endian.h. I believe this file is intended to be generic across architectures.

__BYTE_ORDER is defined to be one of them in /usr/include/bits/endian.h. I think the bits directory contains headers that are specific to a particular architecture.

tcp.h includes <types.h>, which I think should indirectly include these and define the macros. I'm not sure why it's not happening for you.

Barmar
  • 741,623
  • 53
  • 500
  • 612
  • On my system here, `netinet/tcp.h` includes `sys/types.h`, and the only include to `endian.h` I see in there is if `__USE_BSD` is defined – Christian Gibbons Feb 19 '20 at 21:12
  • On my Ubuntu 19.10 machine, `` is included if `__USE_MISC` is defined. However if `__USE_MISC` is not defined then `` never attempts to declare the offending struct in the first place. – Nate Eldredge Feb 19 '20 at 21:18
  • Same here, almost the entire header is inside `#ifdef __USE_MISC`. – Barmar Feb 19 '20 at 21:22
  • Likely something is redefining feature test macros (or the glibc-internal proxies for them like `__USE_MISC`) after the first standard header is included, causing inconsistencies in what is exposed. For example if `` were already included with FTMs that don't expose ``, then later the macros were changed before `` was included, the endian macros would be missing, as OP saw. – R.. GitHub STOP HELPING ICE Feb 19 '20 at 22:12
0

You could use the gcc builtins:

# if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
        uint8_t th_x2:4;        /* (unused) */
        uint8_t th_off:4;       /* data offset */
# endif
# if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
        uint8_t th_off:4;       /* data offset */
        uint8_t th_x2:4;        /* (unused) */
# endif

In the c preprocessor, two macros which do not exist are equal.

Source: https://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html

user3684240
  • 1,420
  • 2
  • 12
  • 18