Detect Endianness with CMake
Asked Answered
T

2

12

My library needs to read-in big-endian integers (4-bytes) and convert them to the endian order of the host for processing. While on *nix ntohl has worked a treat under Windows use of ntohl requires the use of Ws2_32.dll (Winsock).

Such a dependency is one which I would rather eliminate. The simplest way to do this appears to be to write my own endian-swapping function (a trivial exercise, considering performance is not a real concern). However, this requires a way to determine the endianness of the system my library is being compiled on (so I can #ifdef out the swapping function on big endian systems).

As there appears to be no standard preprocessor definition for endianness it appears as if it is necessary to determine it using my build system (cmake). What is the best means of doing this? (I am weary of 'compile a test file and see' type solutions as they would appear to inhibit cross-compiling.)

Tacmahack answered 6/10, 2010 at 22:18 Comment(1)
Remark: CMake actually has reasonable support for cross-compilation. For checks that require running a test program, it builds the test program and then waits for you to set cache variables to the correct result. See paraview.org/Wiki/CMake_Cross_Compiling . Have an upvote for caring about cross compilation.Presuppose
W
7

Edited: I see that cmake has a TestBigEndian.cmake script, but that does a compilation and test run to see if the system is Big Endian or not, which is not what you want to do.

You can check for the system's endianness in your own program with a function like this.

bool isLittleEndian()
{
    short int number = 0x1;
    char *numPtr = (char*)&number;
    return (numPtr[0] == 1);
}

Basically create an integer, and read its first byte (least significant byte). If that byte is 1, then the system is little endian, otherwise it's big endian.

However this doesn't allow you to determine endianness until runtime.

If you want compilation time determination of system endianness, I do not see much alternative aside from the 'building a test program and then compile my real program' a la cmake, or doing exhaustive checks for specific macros defined by compilers, e.g. __BIG_ENDIAN__ on GCC 4.x.

UPDATED You might want to take a look at Boost's own endian.hpp as an example, too. http://www.boost.org/doc/libs/1_43_0/boost/detail/endian.hpp

Waynant answered 6/10, 2010 at 22:28 Comment(3)
"However this doesn't allow you to determine endianness until runtime." - You can do something like this, and it should be evaluated at compile time: const bool g_isLittleEndian=isLittleEndian();Coaler
@Coaler const variable is not strictly evaluated at compile time. It can and will be evaluated at runtime since isLittleEndian() uses variables. To make it strictly evaluated at compile time, keyword constexpr or a template metaprogramming technique should be used. (The reason why I thought const bool g_isLittleEndian=isLittleEndian(); will be evaluated at runtime is because (char*)(& number) is not a constant expression. That's what GCC says when you declare numPtr as constexpr)Lipson
for more info on what can be declared a constexpr, see this linkSubjunctive
J
15

Also this CMake function could do it, http://www.cmake.org/cmake/help/v3.5/module/TestBigEndian.html

include (TestBigEndian)
TEST_BIG_ENDIAN(IS_BIG_ENDIAN)
if(IS_BIG_ENDIAN)
 message(STATUS "BIG_ENDIAN")
else()
 message(STATUS "LITTLE_ENDIAN")
endif()

I think that is supported only from CMake 3.0

Jefferey answered 19/3, 2015 at 16:40 Comment(1)
A note: since CMake 3.20, TestBigEndian is deprecated and CMAKE_<LANG>_BYTE_ORDER is introduced, as its documentation says.Kelson
W
7

Edited: I see that cmake has a TestBigEndian.cmake script, but that does a compilation and test run to see if the system is Big Endian or not, which is not what you want to do.

You can check for the system's endianness in your own program with a function like this.

bool isLittleEndian()
{
    short int number = 0x1;
    char *numPtr = (char*)&number;
    return (numPtr[0] == 1);
}

Basically create an integer, and read its first byte (least significant byte). If that byte is 1, then the system is little endian, otherwise it's big endian.

However this doesn't allow you to determine endianness until runtime.

If you want compilation time determination of system endianness, I do not see much alternative aside from the 'building a test program and then compile my real program' a la cmake, or doing exhaustive checks for specific macros defined by compilers, e.g. __BIG_ENDIAN__ on GCC 4.x.

UPDATED You might want to take a look at Boost's own endian.hpp as an example, too. http://www.boost.org/doc/libs/1_43_0/boost/detail/endian.hpp

Waynant answered 6/10, 2010 at 22:28 Comment(3)
"However this doesn't allow you to determine endianness until runtime." - You can do something like this, and it should be evaluated at compile time: const bool g_isLittleEndian=isLittleEndian();Coaler
@Coaler const variable is not strictly evaluated at compile time. It can and will be evaluated at runtime since isLittleEndian() uses variables. To make it strictly evaluated at compile time, keyword constexpr or a template metaprogramming technique should be used. (The reason why I thought const bool g_isLittleEndian=isLittleEndian(); will be evaluated at runtime is because (char*)(& number) is not a constant expression. That's what GCC says when you declare numPtr as constexpr)Lipson
for more info on what can be declared a constexpr, see this linkSubjunctive

© 2022 - 2024 — McMap. All rights reserved.