introspection.cmake raw

   1  # Copyright (c) 2023-present The Limenka developers
   2  # Distributed under the MIT software license, see the accompanying
   3  # file COPYING or https://opensource.org/license/mit/.
   4  
   5  include(CheckCXXSourceCompiles)
   6  include(CheckCXXSymbolExists)
   7  include(CheckIncludeFileCXX)
   8  
   9  # The following HAVE_{HEADER}_H variables go to the limenka-build-config.h header.
  10  check_include_file_cxx(sys/prctl.h HAVE_SYS_PRCTL_H)
  11  check_include_file_cxx(sys/resources.h HAVE_SYS_RESOURCES_H)
  12  check_include_file_cxx(sys/vmmeter.h HAVE_SYS_VMMETER_H)
  13  check_include_file_cxx(vm/vm_param.h HAVE_VM_VM_PARAM_H)
  14  
  15  check_cxx_symbol_exists(O_CLOEXEC "fcntl.h" HAVE_O_CLOEXEC)
  16  check_cxx_symbol_exists(fdatasync "unistd.h" HAVE_FDATASYNC)
  17  check_cxx_symbol_exists(fork "unistd.h" HAVE_DECL_FORK)
  18  check_cxx_symbol_exists(pipe2 "unistd.h" HAVE_DECL_PIPE2)
  19  check_cxx_symbol_exists(setsid "unistd.h" HAVE_DECL_SETSID)
  20  
  21  check_include_file_cxx(sys/types.h HAVE_SYS_TYPES_H)
  22  check_include_file_cxx(ifaddrs.h HAVE_IFADDRS_H)
  23  if(HAVE_SYS_TYPES_H AND HAVE_IFADDRS_H)
  24    include(TestAppendRequiredLibraries)
  25    test_append_socket_library(core_interface)
  26  endif()
  27  
  28  include(TestAppendRequiredLibraries)
  29  test_append_atomic_library(core_interface)
  30  
  31  check_cxx_symbol_exists(std::system "cstdlib" HAVE_STD_SYSTEM)
  32  check_cxx_symbol_exists(::_wsystem "stdlib.h" HAVE__WSYSTEM)
  33  if(HAVE_STD_SYSTEM OR HAVE__WSYSTEM)
  34    set(HAVE_SYSTEM 1)
  35  endif()
  36  
  37  check_cxx_source_compiles("
  38    #include <string.h>
  39  
  40    int main()
  41    {
  42      char buf[100];
  43      char* p{strerror_r(0, buf, sizeof buf)};
  44      (void)p;
  45    }
  46    " STRERROR_R_CHAR_P
  47  )
  48  
  49  # Check for malloc_info (for memory statistics information in getmemoryinfo).
  50  check_cxx_symbol_exists(malloc_info "malloc.h" HAVE_MALLOC_INFO)
  51  
  52  # Check for mallopt(M_ARENA_MAX) (to set glibc arenas).
  53  check_cxx_source_compiles("
  54    #include <malloc.h>
  55  
  56    int main()
  57    {
  58      mallopt(M_ARENA_MAX, 1);
  59    }
  60    " HAVE_MALLOPT_ARENA_MAX
  61  )
  62  
  63  # Check for posix_fallocate().
  64  check_cxx_source_compiles("
  65    // same as in src/util/fs_helpers.cpp
  66    #ifdef __linux__
  67    #ifdef _POSIX_C_SOURCE
  68    #undef _POSIX_C_SOURCE
  69    #endif
  70    #define _POSIX_C_SOURCE 200112L
  71    #endif // __linux__
  72    #include <fcntl.h>
  73  
  74    int main()
  75    {
  76      return posix_fallocate(0, 0, 0);
  77    }
  78    " HAVE_POSIX_FALLOCATE
  79  )
  80  
  81  # Check for strong getauxval() support in the system headers.
  82  check_cxx_source_compiles("
  83    #include <sys/auxv.h>
  84  
  85    int main()
  86    {
  87      getauxval(AT_HWCAP);
  88    }
  89    " HAVE_STRONG_GETAUXVAL
  90  )
  91  
  92  # Check for UNIX sockets.
  93  check_cxx_source_compiles("
  94    #include <sys/socket.h>
  95    #include <sys/un.h>
  96  
  97    int main()
  98    {
  99      struct sockaddr_un addr;
 100      addr.sun_family = AF_UNIX;
 101    }
 102    " HAVE_SOCKADDR_UN
 103  )
 104  
 105  # Check for close_range().
 106  # NOTE: At least FreeBSD supports the generic variant.
 107  check_cxx_source_compiles("
 108    // same as in src/util/subprocess.cpp
 109    #include <limits.h>
 110    #include <unistd.h>
 111  
 112    int main()
 113    {
 114      return close_range(3, UINT_MAX, 0);
 115    }
 116    " HAVE_CLOSE_RANGE_GENERIC
 117  )
 118  if(NOT HAVE_CLOSE_RANGE_GENERIC)
 119    check_cxx_source_compiles("
 120      // same as in src/util/subprocess.cpp
 121      #define _GNU_SOURCE
 122      #include <linux/close_range.h>
 123      #include <limits.h>
 124      #include <unistd.h>
 125  
 126      int main()
 127      {
 128        return close_range(3, UINT_MAX, 0);
 129      }
 130      " HAVE_CLOSE_RANGE_LINUX
 131    )
 132  endif()
 133  
 134  # Check for different ways of gathering OS randomness:
 135  # - Linux getrandom()
 136  check_cxx_source_compiles("
 137    #include <sys/random.h>
 138  
 139    int main()
 140    {
 141      getrandom(nullptr, 32, 0);
 142    }
 143    " HAVE_GETRANDOM
 144  )
 145  
 146  # - BSD getentropy()
 147  check_cxx_source_compiles("
 148    #include <sys/random.h>
 149  
 150    int main()
 151    {
 152      getentropy(nullptr, 32);
 153    }
 154    " HAVE_GETENTROPY_RAND
 155  )
 156  
 157  
 158  # - BSD sysctl()
 159  check_cxx_source_compiles("
 160    #include <sys/types.h>
 161    #include <sys/sysctl.h>
 162  
 163    #ifdef __linux__
 164    #error Don't use sysctl on Linux, it's deprecated even when it works
 165    #endif
 166  
 167    int main()
 168    {
 169      sysctl(nullptr, 2, nullptr, nullptr, nullptr, 0);
 170    }
 171    " HAVE_SYSCTL
 172  )
 173  
 174  # - BSD sysctl(KERN_ARND)
 175  check_cxx_source_compiles("
 176    #include <sys/types.h>
 177    #include <sys/sysctl.h>
 178  
 179    #ifdef __linux__
 180    #error Don't use sysctl on Linux, it's deprecated even when it works
 181    #endif
 182  
 183    int main()
 184    {
 185      static int name[2] = {CTL_KERN, KERN_ARND};
 186      sysctl(name, 2, nullptr, nullptr, nullptr, 0);
 187    }
 188    " HAVE_SYSCTL_ARND
 189  )
 190  
 191  if(NOT MSVC)
 192    include(CheckSourceCompilesWithFlags)
 193  
 194    # Check for SSE4.1 intrinsics.
 195    set(SSE41_CXXFLAGS -msse4.1)
 196    check_cxx_source_compiles_with_flags([[
 197      #include <immintrin.h>
 198  
 199      #if defined(__clang__)
 200      #pragma clang attribute push(__attribute__((__target__("sse4.1"))), apply_to = function)
 201      __attribute__((__target__("arch=skylake-avx512")))
 202      #elif defined(__GNUC__)
 203      #pragma GCC target ("sse4.1")
 204      #endif
 205  
 206      int main()
 207      {
 208        __m128i a = _mm_set1_epi32(0);
 209        __m128i b = _mm_set1_epi32(1);
 210        __m128i r = _mm_blend_epi16(a, b, 0xFF);
 211        return _mm_extract_epi32(r, 3);
 212      }
 213  
 214      #if defined(__clang__)
 215      #pragma clang attribute pop
 216      #endif
 217      ]] HAVE_SSE41
 218      CXXFLAGS ${SSE41_CXXFLAGS}
 219    )
 220    set(ENABLE_SSE41 ${HAVE_SSE41})
 221  
 222    # Check for AVX2 intrinsics.
 223    set(AVX2_CXXFLAGS -mavx -mavx2)
 224    check_cxx_source_compiles_with_flags([[
 225      #include <immintrin.h>
 226  
 227      #if defined(__clang__)
 228      #pragma clang attribute push(__attribute__((__target__("avx,avx2"))), apply_to = function)
 229      #elif defined(__GNUC__)
 230      #pragma GCC target ("avx,avx2")
 231      #endif
 232  
 233      int main()
 234      {
 235        __m256i l = _mm256_set1_epi32(0);
 236        return _mm256_extract_epi32(l, 7);
 237      }
 238  
 239      #if defined(__clang__)
 240      #pragma clang attribute pop
 241      #endif
 242      ]] HAVE_AVX2
 243      CXXFLAGS ${AVX2_CXXFLAGS}
 244    )
 245    set(ENABLE_AVX2 ${HAVE_AVX2})
 246  
 247    # Check for x86 SHA-NI intrinsics.
 248    set(X86_SHANI_CXXFLAGS -msse4 -msha)
 249    check_cxx_source_compiles_with_flags([[
 250      #include <immintrin.h>
 251  
 252      #if defined(__clang__)
 253      #pragma clang attribute push(__attribute__((__target__("sse4,sse4.1,sha"))), apply_to = function)
 254      #elif defined(__GNUC__)
 255      #pragma GCC target ("sse4,sse4.1,sha")
 256      #endif
 257  
 258      int main()
 259      {
 260        __m128i i = _mm_set1_epi32(0);
 261        __m128i j = _mm_set1_epi32(1);
 262        __m128i k = _mm_set1_epi32(2);
 263        return _mm_extract_epi32(_mm_sha256rnds2_epu32(i, j, k), 0);
 264      }
 265  
 266      #if defined(__clang__)
 267      #pragma clang attribute pop
 268      #endif
 269      ]] HAVE_X86_SHANI
 270      CXXFLAGS ${X86_SHANI_CXXFLAGS}
 271    )
 272    set(ENABLE_X86_SHANI ${HAVE_X86_SHANI})
 273  
 274    # Check for ARMv8 SHA-NI intrinsics.
 275    set(ARM_SHANI_CXXFLAGS -march=armv8-a+crypto)
 276    check_cxx_source_compiles_with_flags([[
 277      #include <arm_neon.h>
 278  
 279      #if defined(__clang__)
 280      #pragma clang attribute push(__attribute__((__target__("armv8-a+crypto"))), apply_to = function)
 281      #elif defined(__GNUC__)
 282      #pragma GCC target ("armv8-a+crypto")
 283      #endif
 284  
 285      int main()
 286      {
 287        uint32x4_t a, b, c;
 288        vsha256h2q_u32(a, b, c);
 289        vsha256hq_u32(a, b, c);
 290        vsha256su0q_u32(a, b);
 291        vsha256su1q_u32(a, b, c);
 292      }
 293  
 294      #if defined(__clang__)
 295      #pragma clang attribute pop
 296      #endif
 297      ]] HAVE_ARM_SHANI
 298      CXXFLAGS ${ARM_SHANI_CXXFLAGS}
 299    )
 300    set(ENABLE_ARM_SHANI ${HAVE_ARM_SHANI})
 301  
 302    # Check for POWER8 vector intrinsics.
 303    function(check_power8_vector VAR)
 304      check_cxx_source_compiles_with_flags([[
 305        #include <altivec.h>
 306        #include <stdint.h>
 307  
 308        int main()
 309        {
 310          unsigned char src[16];
 311          __builtin_crypto_vshasigmaw((__vector uint32_t)vec_vsx_ld(0, src), 1, 0xf);
 312          return 0;
 313        }
 314        ]] ${VAR}
 315        CXXFLAGS ${POWER8_CXXFLAGS}
 316      )
 317    endfunction()
 318    set(POWER8_CXXFLAGS -mpower8-vector)
 319    check_power8_vector(HAVE_POWER8_VECTOR)
 320    set(ENABLE_POWER8 ${HAVE_POWER8_VECTOR})
 321    if(NOT HAVE_POWER8_VECTOR)
 322      set(POWER8_CXXFLAGS -mcpu=power8)
 323      check_power8_vector(HAVE_MCPU_POWER8_FOR_VECTOR)
 324      set(ENABLE_POWER8 ${HAVE_MCPU_POWER8_FOR_VECTOR})
 325    endif()
 326  endif()
 327