BLI: Add easy and portable way of platform-specific checks

Covers OS detection, CPU architecture, bitness, and compiler family.

The goal of this change is to provide easier to use and remember checks
for these things. For example, with this change code like

```
  #ifdef _WIN32
  ...
  #elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) ||     \
      defined(__OpenBSD__)
  ..
  #endif

```

becomes

```
  #if OS_WIN
  ...
  #elif OS_MAC || OS_BSD
  ...
  #endif
```

The code is originally based on build_config.h from Chromium, which was
first modified for Libmv, then to some other projects, and now is
adopted for Blender itself.

The checks are relying on the -Wundef to provide hint of cases when an
include is missing prior to the platform-specific checks.

This change only introduces possibility of cleaner checks and does not
start actual refactor.

Pull Request: https://projects.blender.org/blender/blender/pulls/118908
This commit is contained in:
Sergey Sharybin
2024-08-06 14:33:53 +02:00
committed by Sergey Sharybin
parent 000d34c398
commit baf9691959
3 changed files with 449 additions and 0 deletions
+411
View File
@@ -0,0 +1,411 @@
/* SPDX-FileCopyrightText: 2024 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/**
* Based on Chromium's build_config.h, governed by a BSD-style license,
* with tweaks and extensions needed for the Blender project. */
/**
* Compile-time detection of compiler and hardware platform configuration.
* There are few categories of the defined symbols this header provides.
*
*
* Operating system detection
* ==========================
*
* An operating system is detected is defined as an `OS_<NAME>` symbols. For example, on Windows
* the `OS_WINDOWS` is defined to 1, and all the other symbols prefixed with `OS_` are defined to 0
* (except of the aggregates described above).
*
* There are aggregates which allows to access "family" of the operating system:
*
* - OS_BSD is defined for 1 for all BSD family of OS (FreeBSD, NextBSD, DragonFly...).
* - OS_POSIX is defined to 1 if the OS implements POSIX API.
*
*
* Compiler detection
* ==================
*
* The following compilers are detected: CLANG, GCC, MSVC, MINGW32, MINGW64.
*
* The COMPILER_<family> for the detected compiler is defined to 1, and all the rest of the
* compiler defines are set to 0.
*
* The aggregate COMPILER_MINGW is defined when the compiler is wither MINGW32 or MINGW64.
*
*
* CPU detection
* =============
*
* The commonly detected CPU capabilities are:
* - Family: `ARCH_CPU_<FAMILY>_FAMILY`
* - CPU bitness: `ARCH_CPU_<32|64>_BITS`
* - Endianess: `ARCH_CPU_<LITTLE|BIG>_ENDIAN`
*
* Supported CPU families: X86, S390, PPC, ARM, MIPS.
*/
#pragma once
/**
* All commonly used symbols (which are checked on a "top" level, from outside of any
* platform-specific ifdef block) are to be explicitly defined to 0 when they are not "active".
* Such an approach helps catching cases when one is attempted to access build configuration
* variable without including the header by simply using the -Wundef compiler attribute.
*/
/* -------------------------------------------------------------------- */
/** \name A set of macros to use for platform detection.
* \{ */
#if defined(__native_client__)
/* __native_client__ must be first, so that other OS_ defines are not set. */
# define OS_NACL 1
/* OS_NACL comes in two sandboxing technology flavors, SFI or Non-SFI. PNaCl toolchain defines
* __native_client_nonsfi__ macro in Non-SFI build mode, while it does not in SFI build mode. */
# if defined(__native_client_nonsfi__)
# define OS_NACL_NONSFI
# else
# define OS_NACL_SFI
# endif
#elif defined(_AIX)
# define OS_AIX 1
#elif defined(ANDROID)
# define OS_ANDROID 1
#elif defined(__APPLE__)
/* Only include TargetConditions after testing ANDROID as some android builds on mac don't have
* this header available and it's not needed unless the target is really mac/ios. */
# include <TargetConditionals.h>
# define OS_MAC 1
# if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
# define OS_IOS 1
# endif
#elif defined(__HAIKU__)
# define OS_HAIKU 1
#elif defined(__hpux)
# define OS_HPUX 1
#elif defined(__linux__)
# define OS_LINUX 1
/* Include a system header to pull in features.h for glibc/uclibc macros. */
# include <unistd.h>
# if defined(__GLIBC__) && !defined(__UCLIBC__)
/* We really are using glibc, not uClibc pretending to be glibc. */
# define LIBC_GLIBC 1
# endif
#elif defined(__sgi)
# define OS_IRIX 1
#elif defined(_WIN32)
# define OS_WINDOWS 1
#elif defined(__Fuchsia__)
# define OS_FUCHSIA 1
#elif defined(__DragonFly__)
# define OS_DRAGONFLYBSD 1
#elif defined(__FreeBSD__)
# define OS_FREEBSD 1
#elif defined(__NetBSD__)
# define OS_NETBSD 1
#elif defined(__OpenBSD__)
# define OS_OPENBSD 1
#elif defined(__sun)
# define OS_SOLARIS 1
#elif defined(__QNXNTO__)
# define OS_QNX 1
#elif defined(__asmjs__) || defined(__wasm__)
# define OS_ASMJS 1
#elif defined(__MVS__)
# define OS_ZOS 1
#else
# error Please add support for your platform in BLI_build_config.h
#endif
#if !defined(OS_AIX)
# define OS_AIX 0
#endif
#if !defined(OS_ASMJS)
# define OS_ASMJS 0
#endif
#if !defined(OS_NACL)
# define OS_NACL 0
#endif
#if !defined(OS_NACL_NONSFI)
# define OS_NACL_NONSFI 0
#endif
#if !defined(OS_NACL_SFI)
# define OS_NACL_SFI 0
#endif
#if !defined(OS_ANDROID)
# define OS_ANDROID 0
#endif
#if !defined(OS_MAC)
# define OS_MAC 0
#endif
#if !defined(OS_IOS)
# define OS_IOS 0
#endif
#if !defined(OS_HAIKU)
# define OS_HAIKU 0
#endif
#if !defined(OS_HPUX)
# define OS_HPUX 0
#endif
#if !defined(OS_IRIX)
# define OS_IRIX 0
#endif
#if !defined(OS_LINUX)
# define OS_LINUX 0
#endif
#if !defined(LIBC_GLIBC)
# define LIBC_GLIBC 0
#endif
#if !defined(OS_WINDOWS)
# define OS_WINDOWS 0
#endif
#if !defined(OS_FUCHSIA)
# define OS_FUCHSIA 0
#endif
#if !defined(OS_DRAGONFLYBSD)
# define OS_DRAGONFLYBSD 0
#endif
#if !defined(OS_FREEBSD)
# define OS_FREEBSD 0
#endif
#if !defined(OS_NETBSD)
# define OS_NETBSD 0
#endif
#if !defined(OS_OPENBSD)
# define OS_OPENBSD 0
#endif
#if !defined(OS_SOLARIS)
# define OS_SOLARIS 0
#endif
#if !defined(OS_QNX)
# define OS_QNX 0
#endif
#if !defined(OS_ZOS)
# define OS_ZOS 0
#endif
/** \} */
/* -------------------------------------------------------------------- */
/** \name *BSD OS family detection.
* For access to standard BSD features, use OS_BSD instead of a more specific macro.
* \{ */
#if OS_DRAGONFLYBSD || OS_FREEBSD || OS_OPENBSD || OS_NETBSD
# define OS_BSD 1
#else
# define OS_BSD 0
#endif
/** \} */
/* -------------------------------------------------------------------- */
/** \name POSIX system detection.
* For access to standard POSIXish features use OS_POSIX instead of a more specific macro.
* \{ */
#if OS_AIX || OS_ANDROID || OS_ASMJS || OS_FREEBSD || OS_LINUX || OS_MAC || OS_NACL || \
OS_NETBSD || OS_OPENBSD || OS_QNX || OS_SOLARIS
# define OS_POSIX 1
#else
# define OS_POSIX 0
#endif
/** \} */
/* -------------------------------------------------------------------- */
/** \name Compiler detection, including its capabilities.
* \{ */
#if defined(__clang__)
# define COMPILER_CLANG 1
#elif defined(__GNUC__)
# define COMPILER_GCC 1
# define COMPILER_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
#elif defined(_MSC_VER)
# define COMPILER_MSVC 1
# define COMPILER_MSVC_VERSION (_MSC_VER)
#elif defined(__MINGW32__)
# define COMPILER_MINGW32 1
#elif defined(__MINGW64__)
# define COMPILER_MINGW64 1
#else
# error Please add support for your compiler in BLI_build_config.h
#endif
#if !defined(COMPILER_CLANG)
# define COMPILER_CLANG 0
#endif
#if !defined(COMPILER_GCC)
# define COMPILER_GCC 0
#endif
#if !defined(COMPILER_MSVC)
# define COMPILER_MSVC 0
#endif
#if !defined(COMPILER_MINGW32)
# define COMPILER_MINGW32 0
#endif
#if !defined(COMPILER_MINGW64)
# define COMPILER_MINGW64 0
#endif
/* Compiler is any of MinGW family. */
#if COMPILER_MINGW32 || COMPILER_MINGW64
# define COMPILER_MINGW 1
#else
# define COMPILER_MINGW 0
#endif
/** \} */
/* -------------------------------------------------------------------- */
/** \name Processor architecture detection.
* For more info on what's defined, see:
*
* http://msdn.microsoft.com/en-us/library/b0084kay.aspx
* http://www.agner.org/optimize/calling_conventions.pdf
*
* or with gcc, run: "echo | gcc -E -dM -"
* \{ */
#if defined(_M_X64) || defined(__x86_64__)
# define ARCH_CPU_X86_FAMILY 1
# define ARCH_CPU_X86_64 1
# define ARCH_CPU_64_BITS 1
# define ARCH_CPU_LITTLE_ENDIAN 1
#elif defined(_M_IX86) || defined(__i386__)
# define ARCH_CPU_X86_FAMILY 1
# define ARCH_CPU_X86 1
# define ARCH_CPU_32_BITS 1
# define ARCH_CPU_LITTLE_ENDIAN 1
#elif defined(__s390x__)
# define ARCH_CPU_S390_FAMILY 1
# define ARCH_CPU_S390X 1
# define ARCH_CPU_64_BITS 1
# define ARCH_CPU_BIG_ENDIAN 1
#elif defined(__s390__)
# define ARCH_CPU_S390_FAMILY 1
# define ARCH_CPU_S390 1
# define ARCH_CPU_31_BITS 1
# define ARCH_CPU_BIG_ENDIAN 1
#elif (defined(__PPC64__) || defined(__PPC__)) && defined(__BIG_ENDIAN__)
# define ARCH_CPU_PPC64_FAMILY 1
# define ARCH_CPU_PPC64 1
# define ARCH_CPU_64_BITS 1
# define ARCH_CPU_BIG_ENDIAN 1
#elif defined(__PPC64__)
# define ARCH_CPU_PPC64_FAMILY 1
# define ARCH_CPU_PPC64 1
# define ARCH_CPU_64_BITS 1
# define ARCH_CPU_LITTLE_ENDIAN 1
#elif defined(__ARMEL__)
# define ARCH_CPU_ARM_FAMILY 1
# define ARCH_CPU_ARMEL 1
# define ARCH_CPU_32_BITS 1
# define ARCH_CPU_LITTLE_ENDIAN 1
#elif defined(__aarch64__) || defined(_M_ARM64)
# define ARCH_CPU_ARM_FAMILY 1
# define ARCH_CPU_ARM64 1
# define ARCH_CPU_64_BITS 1
# define ARCH_CPU_LITTLE_ENDIAN 1
#elif defined(__pnacl__) || defined(__asmjs__) || defined(__wasm__)
# define ARCH_CPU_32_BITS 1
# define ARCH_CPU_LITTLE_ENDIAN 1
#elif defined(__MIPSEL__)
# if defined(__LP64__)
# define ARCH_CPU_MIPS_FAMILY 1
# define ARCH_CPU_MIPS64EL 1
# define ARCH_CPU_64_BITS 1
# define ARCH_CPU_LITTLE_ENDIAN 1
# else
# define ARCH_CPU_MIPS_FAMILY 1
# define ARCH_CPU_MIPSEL 1
# define ARCH_CPU_32_BITS 1
# define ARCH_CPU_LITTLE_ENDIAN 1
# endif
#elif defined(__MIPSEB__)
# if defined(__LP64__)
# define ARCH_CPU_MIPS_FAMILY 1
# define ARCH_CPU_MIPS64 1
# define ARCH_CPU_64_BITS 1
# define ARCH_CPU_BIG_ENDIAN 1
# else
# define ARCH_CPU_MIPS_FAMILY 1
# define ARCH_CPU_MIPS 1
# define ARCH_CPU_32_BITS 1
# define ARCH_CPU_BIG_ENDIAN 1
# endif
#else
# error Please add support for your architecture in BLI_build_config.h
#endif
#if !defined(ARCH_CPU_LITTLE_ENDIAN)
# define ARCH_CPU_LITTLE_ENDIAN 0
#endif
#if !defined(ARCH_CPU_BIG_ENDIAN)
# define ARCH_CPU_BIG_ENDIAN 0
#endif
#if !defined(ARCH_CPU_31_BITS)
# define ARCH_CPU_31_BITS 0
#endif
#if !defined(ARCH_CPU_32_BITS)
# define ARCH_CPU_32_BITS 0
#endif
#if !defined(ARCH_CPU_64_BITS)
# define ARCH_CPU_64_BITS 0
#endif
#if !defined(ARCH_CPU_X86_FAMILY)
# define ARCH_CPU_X86_FAMILY 0
#endif
#if !defined(ARCH_CPU_ARM_FAMILY)
# define ARCH_CPU_ARM_FAMILY 0
#endif
#if !defined(ARCH_CPU_MIPS_FAMILY)
# define ARCH_CPU_MIPS_FAMILY 0
#endif
#if !defined(ARCH_CPU_PPC64_FAMILY)
# define ARCH_CPU_PPC64_FAMILY 0
#endif
#if !defined(ARCH_CPU_S390_FAMILY)
# define ARCH_CPU_S390_FAMILY 0
#endif
#if !defined(ARCH_CPU_ARM64)
# define ARCH_CPU_ARM64 0
#endif
#if !defined(ARCH_CPU_ARMEL)
# define ARCH_CPU_ARMEL 0
#endif
#if !defined(ARCH_CPU_MIPS)
# define ARCH_CPU_MIPS 0
#endif
#if !defined(ARCH_CPU_MIPS64)
# define ARCH_CPU_MIPS64 0
#endif
#if !defined(ARCH_CPU_MIPS64EL)
# define ARCH_CPU_MIPS64EL 0
#endif
#if !defined(ARCH_CPU_MIPSEL)
# define ARCH_CPU_MIPSEL 0
#endif
#if !defined(ARCH_CPU_PPC64)
# define ARCH_CPU_PPC64 0
#endif
#if !defined(ARCH_CPU_S390)
# define ARCH_CPU_S390 0
#endif
#if !defined(ARCH_CPU_S390X)
# define ARCH_CPU_S390X 0
#endif
#if !defined(ARCH_CPU_X86)
# define ARCH_CPU_X86 0
#endif
#if !defined(ARCH_CPU_X86_64)
# define ARCH_CPU_X86_64 0
#endif
/** \} */
+2
View File
@@ -198,6 +198,7 @@ set(SRC
BLI_bounds.hh
BLI_bounds_types.hh
BLI_boxpack_2d.h
BLI_build_config.h
BLI_buffer.h
BLI_cache_mutex.hh
BLI_color.hh
@@ -510,6 +511,7 @@ if(WITH_GTESTS)
tests/BLI_bit_ref_test.cc
tests/BLI_bit_span_test.cc
tests/BLI_bit_vector_test.cc
tests/BLI_build_config_test.cc
tests/BLI_bitmap_test.cc
tests/BLI_bounds_test.cc
tests/BLI_color_test.cc
@@ -0,0 +1,36 @@
/* SPDX-FileCopyrightText: 2024 Blender Authors
*
* SPDX-License-Identifier: Apache-2.0 */
#include "testing/testing.h"
#include "BLI_build_config.h"
#include "BLI_endian_defines.h"
namespace blender::tests {
/* Some basic tests to ensure simple code compiles, and that there are no obvious mistakes in the
* build_config implementation. */
TEST(BLI_build_config, Basic)
{
static_assert(ARCH_CPU_31_BITS || ARCH_CPU_32_BITS || ARCH_CPU_64_BITS);
}
TEST(BLI_build_config, Endian)
{
/* TODO: This could become more comprehensive test when C++20 is available: we can check that
* std::endian::native is aligned with the compile-time defines. */
static_assert(ARCH_CPU_LITTLE_ENDIAN || ARCH_CPU_BIG_ENDIAN);
/* Verify the build_config is aligned with the CMake configuration. */
#if defined(__BIG_ENDIAN__)
static_assert(ARCH_CPU_BIG_ENDIAN);
static_assert(!ARCH_CPU_LITTLE_ENDIAN);
#endif
#if defined(__LITTLE_ENDIAN__)
static_assert(!ARCH_CPU_BIG_ENDIAN);
static_assert(ARCH_CPU_LITTLE_ENDIAN);
#endif
}
} // namespace blender::tests