SDL icon indicating copy to clipboard operation
SDL copied to clipboard

Is there no way for the CMake configure step to do checks faster or disable them?

Open Please-just-dont opened this issue 3 months ago • 16 comments

I'm talking about stuff like this:

Looking for strnstr
Looking for strnstr - not found
Looking for strtod
Looking for strtod - found
Looking for strtok_r
Looking for strtok_r - found
Looking for strtol
Looking for strtol - found
Looking for strtoll
Looking for strtoll - found
Looking for strtoul
Looking for strtoul - found
Looking for strtoull
Looking for strtoull - found
Looking for tan
Looking for tan - found
Looking for tanf
Looking for tanf - found
Looking for trunc
Looking for trunc - found
Looking for truncf
Looking for truncf - found
Looking for unsetenv
Looking for unsetenv - found
Looking for vsnprintf
Looking for vsnprintf - found
Looking for vsscanf
Looking for vsscanf - found
Looking for wcsnlen
Looking for wcsnlen - found
Looking for wcscmp
Looking for wcscmp - found
Looking for wcsdup
Looking for wcsdup - found
Looking for wcslcat
Looking for wcslcat - found
Looking for wcslcpy
Looking for wcslcpy - found
Looking for wcslen
Looking for wcslen - found
Looking for wcsncmp
Looking for wcsncmp - found
Looking for wcsstr
Looking for wcsstr - found
Looking for wcstol
Looking for wcstol - found
Looking for strcasestr
Looking for strcasestr - found
Performing Test LIBC_HAS_ISINF
Performing Test LIBC_HAS_ISINF - Success
Performing Test LIBC_ISINF_HANDLES_FLOAT
Performing Test LIBC_ISINF_HANDLES_FLOAT - Success
Performing Test LIBC_HAS_ISINFF
Performing Test LIBC_HAS_ISINFF - Success

This takes a very long time. I know that these are cached and only run once, but many times I clear the cache when trying new stuff and it's very annoying. I did a search for "Looking for" and I didn't find any in any CMakeLists.txt file, where are these happening? And is there a better way to do this?

Please-just-dont avatar Sep 20 '25 06:09 Please-just-dont

These tests can be found in the main CMakelists, if you grep for the name of the symbols.

For a few toolchains, we preseed the cache, causing these tests to be skipped.

The unix scene is too diverse to preseed the cache: there is too much variety to assume anything.

I suppose you can speed things up by using some heuristic algorithms. E.g. combining multiple tests, and dividing on failure. But such frameworks do not exist.

madebr avatar Sep 20 '25 10:09 madebr

One thing worth mentioning is that using clang (not clang-cl) on Windows skips the preseed cache. Looking at that file, it seems that most of it does not actually depend on having a cl-style compiler, so it may be worth it to try and loosen the outermost if(MSVC) check and then sprinkle it back in only where it matters, like when checking for /W3.

e4m2 avatar Sep 20 '25 18:09 e4m2

This has always driven me nuts (in CMake as well as autoconf). Before we preseeded Emscripten, these checks would take an eternity.

It's all compile/link time. I wonder if there is some way we could build something that checks all symbols with a single build and parses out linker errors.

icculus avatar Sep 20 '25 20:09 icculus

Is it possible to run them in parallel?

maia-s avatar Sep 20 '25 22:09 maia-s

I ran some experiments last year, but it only works in C++20 mode and is theoretically IFNDR https://github.com/madebr/cmake-symbol-test

It's worth to explore Icculus' suggestion about parsing link errors.

madebr avatar Sep 20 '25 23:09 madebr

If not cross compiling we could check for syms with dlsym

maia-s avatar Sep 20 '25 23:09 maia-s

Could it run all the commonly supported things in one test, and if that test fails then it'd fall back to individual checks? That seems simpler than parsing errors to me, at least.

edit: I suppose that's what @madebr was suggesting earlier

slime73 avatar Sep 21 '25 01:09 slime73

@icculus The thing is I like the concept of prechecks, so this is a cool feature, but I mean, it DOES take a long time, and things like:

Looking for strtod - found Looking for strtok_r Looking for strtok_r - found Looking for strtol Looking for strtol - found Looking for strtoll Looking for strtoll - found Looking for strtoul Looking for strtoul - found Looking for strtoull Looking for strtoull - found

I understand it's trying to compile and link these, I'd probably just rather get an undefined reference error from the compiler and it'll be obvious that something is really wrong.

Please-just-dont avatar Sep 21 '25 03:09 Please-just-dont

But the problem is nothing is wrong either way; we're deciding if we need our internal fallbacks for various functions or not, not whether the library will fail to build.

icculus avatar Sep 21 '25 03:09 icculus

Failing everything else, it should at least be possible to group together tests that are likely to succeed together and only try fine grained tests if that fails. E.g. have a test that tries to use most or all of the strto* functions, and only try testing functions from that individually if the catch all one fails. Could be done in several layers if you want to get fancy

maia-s avatar Sep 21 '25 03:09 maia-s

This deserves more attention. Our usecase is running CI builds for Windows and Linux after every commit with GitHub Actions. The longest-running build takes 3:59 minutes, 1:59 of which is just the SDL3 configure step...

The alternative would be using prebuilt SDL3. I guess that's less of an inconvenience compared to bearing the x2 CI runtime.

nonk123 avatar Dec 09 '25 14:12 nonk123

@nonk123 Yes, I agree. I'm on a very fast CPU, a 14700k, which has 20 cores and 28 threads (if that makes a difference, not sure if this is single threaded) and it takes 20 seconds for me. And way slower on my other CPUs. Just a reminder of what it runs through. Oh just out of curiosity, what's the point of doing stuff like -- Looking for math.h -- Looking for math.h - found, I mean if it just fails when you attempt to use it, is it that bad? I dunno:

-- Found PkgConfig: /usr/bin/pkg-config (found version "1.8.1")
-- Detecting Target CPU Architecture
-- Detecting Target CPU Architecture - X64
-- Performing Test HAVE_GCC_WALL
-- Performing Test HAVE_GCC_WALL - Success
-- Performing Test HAVE_GCC_WUNDEF
-- Performing Test HAVE_GCC_WUNDEF - Success
-- Performing Test HAVE_GCC_WFLOAT_CONVERSION
-- Performing Test HAVE_GCC_WFLOAT_CONVERSION - Success
-- Performing Test HAVE_GCC_NO_STRICT_ALIASING
-- Performing Test HAVE_GCC_NO_STRICT_ALIASING - Success
-- Performing Test HAVE_GCC_WDOCUMENTATION
-- Performing Test HAVE_GCC_WDOCUMENTATION - Success
-- Performing Test HAVE_GCC_WDOCUMENTATION_UNKNOWN_COMMAND
-- Performing Test HAVE_GCC_WDOCUMENTATION_UNKNOWN_COMMAND - Success
-- Performing Test HAVE_GCC_COMMENT_BLOCK_COMMANDS
-- Performing Test HAVE_GCC_COMMENT_BLOCK_COMMANDS - Success
-- Performing Test HAVE_GCC_WSHADOW
-- Performing Test HAVE_GCC_WSHADOW - Success
-- Performing Test HAVE_GCC_WUNUSED_LOCAL_TYPEDEFS
-- Performing Test HAVE_GCC_WUNUSED_LOCAL_TYPEDEFS - Success
-- Performing Test HAVE_GCC_WIMPLICIT_FALLTHROUGH
-- Performing Test HAVE_GCC_WIMPLICIT_FALLTHROUGH - Success
-- Performing Test COMPILER_SUPPORTS_FCOLOR_DIAGNOSTICS
-- Performing Test COMPILER_SUPPORTS_FCOLOR_DIAGNOSTICS - Success
-- Looking for __GLIBC__
-- Looking for __GLIBC__ - found
-- Performing Test HAVE_WL_VERSION_SCRIPT
-- Performing Test HAVE_WL_VERSION_SCRIPT - Success
-- Performing Test COMPILER_SUPPORTS_GCC_ATOMICS
-- Performing Test COMPILER_SUPPORTS_GCC_ATOMICS - Success
-- Performing Test HAVE_GCC_FVISIBILITY
-- Performing Test HAVE_GCC_FVISIBILITY - Success
-- Performing Test LINKER_SUPPORTS_WL_NO_UNDEFINED
-- Performing Test LINKER_SUPPORTS_WL_NO_UNDEFINED - Success
-- Performing Test COMPILER_SUPPORTS_MMX
-- Performing Test COMPILER_SUPPORTS_MMX - Success
-- Performing Test COMPILER_SUPPORTS_SSE
-- Performing Test COMPILER_SUPPORTS_SSE - Success
-- Performing Test COMPILER_SUPPORTS_SSE2
-- Performing Test COMPILER_SUPPORTS_SSE2 - Success
-- Performing Test COMPILER_SUPPORTS_SSE3
-- Performing Test COMPILER_SUPPORTS_SSE3 - Success
-- Performing Test COMPILER_SUPPORTS_SSE4_1
-- Performing Test COMPILER_SUPPORTS_SSE4_1 - Success
-- Performing Test COMPILER_SUPPORTS_SSE4_2
-- Performing Test COMPILER_SUPPORTS_SSE4_2 - Success
-- Performing Test COMPILER_SUPPORTS_AVX
-- Performing Test COMPILER_SUPPORTS_AVX - Success
-- Performing Test COMPILER_SUPPORTS_AVX2
-- Performing Test COMPILER_SUPPORTS_AVX2 - Success
-- Performing Test COMPILER_SUPPORTS_AVX512F
-- Performing Test COMPILER_SUPPORTS_AVX512F - Success
-- Looking for alloca.h
-- Looking for alloca.h - found
-- Looking for float.h
-- Looking for float.h - found
-- Looking for iconv.h
-- Looking for iconv.h - found
-- Looking for inttypes.h
-- Looking for inttypes.h - found
-- Looking for limits.h
-- Looking for limits.h - found
-- Looking for malloc.h
-- Looking for malloc.h - found
-- Looking for math.h
-- Looking for math.h - found
-- Looking for memory.h
-- Looking for memory.h - found
-- Looking for signal.h
-- Looking for signal.h - found
-- Looking for stdarg.h
-- Looking for stdarg.h - found
-- Looking for stdbool.h
-- Looking for stdbool.h - found
-- Looking for stddef.h
-- Looking for stddef.h - found
-- Looking for stdint.h
-- Looking for stdint.h - found
-- Looking for stdio.h
-- Looking for stdio.h - found
-- Looking for stdlib.h
-- Looking for stdlib.h - found
-- Looking for string.h
-- Looking for string.h - found
-- Looking for strings.h
-- Looking for strings.h - found
-- Looking for sys/types.h
-- Looking for sys/types.h - found
-- Looking for time.h
-- Looking for time.h - found
-- Looking for wchar.h
-- Looking for wchar.h - found
-- Looking for pow in m
-- Looking for pow in m - found
-- Looking for abs
-- Looking for abs - found
-- Looking for acos
-- Looking for acos - found
-- Looking for acosf
-- Looking for acosf - found
-- Looking for asin
-- Looking for asin - found
-- Looking for asinf
-- Looking for asinf - found
-- Looking for atan
-- Looking for atan - found
-- Looking for atan2
-- Looking for atan2 - found
-- Looking for atan2f
-- Looking for atan2f - found
-- Looking for atanf
-- Looking for atanf - found
-- Looking for atof
-- Looking for atof - found
-- Looking for atoi
-- Looking for atoi - found
-- Looking for bcopy
-- Looking for bcopy - found
-- Looking for ceil
-- Looking for ceil - found
-- Looking for ceilf
-- Looking for ceilf - found
-- Looking for copysign
-- Looking for copysign - found
-- Looking for copysignf
-- Looking for copysignf - found
-- Looking for cos
-- Looking for cos - found
-- Looking for cosf
-- Looking for cosf - found
-- Looking for _Exit
-- Looking for _Exit - found
-- Looking for exp
-- Looking for exp - found
-- Looking for expf
-- Looking for expf - found
-- Looking for fabs
-- Looking for fabs - found
-- Looking for fabsf
-- Looking for fabsf - found
-- Looking for floor
-- Looking for floor - found
-- Looking for floorf
-- Looking for floorf - found
-- Looking for fmod
-- Looking for fmod - found
-- Looking for fmodf
-- Looking for fmodf - found
-- Looking for fopen64
-- Looking for fopen64 - found
-- Looking for fseeko
-- Looking for fseeko - found
-- Looking for fseeko64
-- Looking for fseeko64 - found
-- Looking for getenv
-- Looking for getenv - found
-- Looking for _i64toa
-- Looking for _i64toa - not found
-- Looking for index
-- Looking for index - found
-- Looking for itoa
-- Looking for itoa - not found
-- Looking for log
-- Looking for log - found
-- Looking for log10
-- Looking for log10 - found
-- Looking for log10f
-- Looking for log10f - found
-- Looking for logf
-- Looking for logf - found
-- Looking for lround
-- Looking for lround - found
-- Looking for lroundf
-- Looking for lroundf - found
-- Looking for _ltoa
-- Looking for _ltoa - not found
-- Looking for malloc
-- Looking for malloc - found
-- Looking for memcmp
-- Looking for memcmp - found
-- Looking for memcpy
-- Looking for memcpy - found
-- Looking for memmove
-- Looking for memmove - found
-- Looking for memset
-- Looking for memset - found
-- Looking for modf
-- Looking for modf - found
-- Looking for modff
-- Looking for modff - found
-- Looking for pow
-- Looking for pow - found
-- Looking for powf
-- Looking for powf - found
-- Looking for putenv
-- Looking for putenv - found
-- Looking for rindex
-- Looking for rindex - found
-- Looking for round
-- Looking for round - found
-- Looking for roundf
-- Looking for roundf - found
-- Looking for scalbn
-- Looking for scalbn - found
-- Looking for scalbnf
-- Looking for scalbnf - found
-- Looking for setenv
-- Looking for setenv - found
-- Looking for sin
-- Looking for sin - found
-- Looking for sinf
-- Looking for sinf - found
-- Looking for sqr
-- Looking for sqr - not found
-- Looking for sqrt
-- Looking for sqrt - found
-- Looking for sqrtf
-- Looking for sqrtf - found
-- Looking for sscanf
-- Looking for sscanf - found
-- Looking for strchr
-- Looking for strchr - found
-- Looking for strcmp
-- Looking for strcmp - found
-- Looking for strlcat
-- Looking for strlcat - found
-- Looking for strlcpy
-- Looking for strlcpy - found
-- Looking for strlen
-- Looking for strlen - found
-- Looking for strncmp
-- Looking for strncmp - found
-- Looking for strnlen
-- Looking for strnlen - found
-- Looking for strpbrk
-- Looking for strpbrk - found
-- Looking for strrchr
-- Looking for strrchr - found
-- Looking for strstr
-- Looking for strstr - found
-- Looking for strnstr
-- Looking for strnstr - not found
-- Looking for strtod
-- Looking for strtod - found
-- Looking for strtok_r
-- Looking for strtok_r - found
-- Looking for strtol
-- Looking for strtol - found
-- Looking for strtoll
-- Looking for strtoll - found
-- Looking for strtoul
-- Looking for strtoul - found
-- Looking for strtoull
-- Looking for strtoull - found
-- Looking for tan
-- Looking for tan - found
-- Looking for tanf
-- Looking for tanf - found
-- Looking for trunc
-- Looking for trunc - found
-- Looking for truncf
-- Looking for truncf - found
-- Looking for unsetenv
-- Looking for unsetenv - found
-- Looking for vsnprintf
-- Looking for vsnprintf - found
-- Looking for vsscanf
-- Looking for vsscanf - found
-- Looking for wcsnlen
-- Looking for wcsnlen - found
-- Looking for wcscmp
-- Looking for wcscmp - found
-- Looking for wcsdup
-- Looking for wcsdup - found
-- Looking for wcslcat
-- Looking for wcslcat - found
-- Looking for wcslcpy
-- Looking for wcslcpy - found
-- Looking for wcslen
-- Looking for wcslen - found
-- Looking for wcsncmp
-- Looking for wcsncmp - found
-- Looking for wcsstr
-- Looking for wcsstr - found
-- Looking for wcstol
-- Looking for wcstol - found
-- Looking for strcasestr
-- Looking for strcasestr - found
-- Performing Test LIBC_HAS_ISINF
-- Performing Test LIBC_HAS_ISINF - Success
-- Performing Test LIBC_ISINF_HANDLES_FLOAT
-- Performing Test LIBC_ISINF_HANDLES_FLOAT - Success
-- Performing Test LIBC_HAS_ISINFF
-- Performing Test LIBC_HAS_ISINFF - Success
-- Performing Test LIBC_HAS_ISNAN
-- Performing Test LIBC_HAS_ISNAN - Success
-- Performing Test LIBC_ISNAN_HANDLES_FLOAT
-- Performing Test LIBC_ISNAN_HANDLES_FLOAT - Success
-- Performing Test LIBC_HAS_ISNANF
-- Performing Test LIBC_HAS_ISNANF - Success
-- Looking for fdatasync
-- Looking for fdatasync - found
-- Looking for gethostname
-- Looking for gethostname - found
-- Looking for getpagesize
-- Looking for getpagesize - found
-- Looking for sigaction
-- Looking for sigaction - found
-- Looking for sigtimedwait
-- Looking for sigtimedwait - found
-- Looking for setjmp
-- Looking for setjmp - found
-- Looking for nanosleep
-- Looking for nanosleep - found
-- Looking for gmtime_r
-- Looking for gmtime_r - found
-- Looking for localtime_r
-- Looking for localtime_r - found
-- Looking for nl_langinfo
-- Looking for nl_langinfo - found
-- Looking for sysconf
-- Looking for sysconf - found
-- Looking for sysctlbyname
-- Looking for sysctlbyname - not found
-- Looking for getauxval
-- Looking for getauxval - found
-- Looking for elf_aux_info
-- Looking for elf_aux_info - not found
-- Looking for ppoll
-- Looking for ppoll - found
-- Looking for memfd_create
-- Looking for memfd_create - found
-- Looking for posix_fallocate
-- Looking for posix_fallocate - found
-- Looking for posix_spawn_file_actions_addchdir
-- Looking for posix_spawn_file_actions_addchdir - not found
-- Looking for posix_spawn_file_actions_addchdir_np
-- Looking for posix_spawn_file_actions_addchdir_np - found
-- Performing Test ICONV_IN_LIBC
-- Performing Test ICONV_IN_LIBC - Success
-- Performing Test ICONV_IN_LIBICONV
-- Performing Test ICONV_IN_LIBICONV - Failed
-- Performing Test HAVE_SA_SIGACTION
-- Performing Test HAVE_SA_SIGACTION - Success
-- Performing Test HAVE_ST_MTIM
-- Performing Test HAVE_ST_MTIM - Success
-- Looking for dlopen
-- Looking for dlopen - found
-- Performing Test HAVE_O_CLOEXEC
-- Performing Test HAVE_O_CLOEXEC - Success
-- Checking for module 'jack'
--   Package 'jack', required by 'virtual:world', not found
-- Checking for module 'libpipewire-0.3>=0.3.44'
--   Package 'libpipewire-0.3', required by 'virtual:world', not found
-- Checking for module 'libpulse>=0.9.15'
--   Found libpulse, version 16.1
-- dynamic libpulse -> libpulse.so.0
-- Checking for module 'sndio'
--   Found sndio, version 1.9.0
-- dynamic libsndio -> libsndio.so.7
-- Found X11: /usr/include
-- Looking for XOpenDisplay in /usr/lib/x86_64-linux-gnu/libX11.so;/usr/lib/x86_64-linux-gnu/libXext.so
-- Looking for XOpenDisplay in /usr/lib/x86_64-linux-gnu/libX11.so;/usr/lib/x86_64-linux-gnu/libXext.so - found
-- Looking for gethostbyname
-- Looking for gethostbyname - found
-- Looking for connect
-- Looking for connect - found
-- Looking for remove
-- Looking for remove - found
-- Looking for shmat
-- Looking for shmat - found
-- Looking for IceConnectionNumber in ICE
-- Looking for IceConnectionNumber in ICE - found
-- dynamic libX11 -> libX11.so.6
-- dynamic libXext -> libXext.so.6
-- dynamic libXcursor -> libXcursor.so.1
-- dynamic libXi -> libXi.so.6
-- dynamic libXfixes -> libXfixes.so.3
-- dynamic libXrandr -> libXrandr.so.2
-- dynamic libXrender -> libXrender.so.1
-- dynamic libXss -> libXss.so.1
-- dynamic libXtst -> libXtst.so.6
-- Looking for shmat
-- Looking for shmat - found
-- Performing Test HAVE_XGENERICEVENT
-- Performing Test HAVE_XGENERICEVENT - Success
-- Looking for X11/XKBlib.h
-- Looking for X11/XKBlib.h - found
-- Performing Test HAVE_XINPUT2_SCROLLINFO
-- Performing Test HAVE_XINPUT2_SCROLLINFO - Success
-- Performing Test HAVE_XINPUT2_MULTITOUCH
-- Performing Test HAVE_XINPUT2_MULTITOUCH - Success
-- Performing Test HAVE_XINPUT2_GESTURE
-- Performing Test HAVE_XINPUT2_GESTURE - Success
-- Performing Test HAVE_XFIXES_H
-- Performing Test HAVE_XFIXES_H - Success
-- Checking for module 'libdrm'
--   Found libdrm, version 2.4.122
-- Checking for module 'gbm'
--   Found gbm, version 25.0.7-0ubuntu0.24.04.2
-- Checking for modules 'wayland-client>=1.18;wayland-egl;wayland-cursor;egl;xkbcommon>=0.5.0'
--   Found wayland-client, version 1.22.0
--   Found wayland-egl, version 18.1.0
--   Found wayland-cursor, version 1.22.0
--   Found egl, version 1.5
--   Found xkbcommon, version 1.6.0
-- dynamic libwayland-client -> libwayland-client.so.0
-- dynamic libwayland-egl -> libwayland-egl.so.1
-- dynamic libwayland-cursor -> libwayland-cursor.so.0
-- dynamic libxkbcommon -> libxkbcommon.so.0
-- Checking for module 'libdecor-0'
--   Found libdecor-0, version 0.2.2
-- dynamic libdecor-0 -> libdecor-0.so.0
-- Performing Test HAVE_LINUX_INPUT_H
-- Performing Test HAVE_LINUX_INPUT_H - Success
-- Performing Test HAVE_INPUT_KD
-- Performing Test HAVE_INPUT_KD - Success
-- Performing Test HAVE_LINUX_VIDEODEV2_H
-- Performing Test HAVE_LINUX_VIDEODEV2_H - Success
-- Looking for libudev.h
-- Looking for libudev.h - found
-- dynamic libudev -> libudev.so.1
-- Looking for sys/inotify.h
-- Looking for sys/inotify.h - found
-- Looking for inotify_init
-- Looking for inotify_init - found
-- Looking for inotify_init1
-- Looking for inotify_init1 - found
-- Checking for one of the modules 'dbus-1;dbus'
-- Checking for one of the modules 'ibus-1.0;ibus'
-- Checking for one of the modules 'liburing-ffi'
-- Checking for module 'libusb-1.0>=1.0.16'
--   Package 'libusb-1.0', required by 'virtual:world', not found
-- Could NOT find LibUSB (missing: LibUSB_LIBRARY LibUSB_INCLUDE_PATH) (found version "LibUSB_VERSION-NOTFOUND")
-- Performing Test HAVE_PTHREADS
-- Performing Test HAVE_PTHREADS - Success
-- Performing Test HAVE_RECURSIVE_MUTEXES
-- Performing Test HAVE_RECURSIVE_MUTEXES - Success
-- Performing Test HAVE_PTHREADS_SEM
-- Performing Test HAVE_PTHREADS_SEM - Success
-- Performing Test COMPILER_HAS_SEM_TIMEDWAIT
-- Performing Test COMPILER_HAS_SEM_TIMEDWAIT - Success
-- Looking for pthread.h
-- Looking for pthread.h - found
-- Looking for pthread_np.h
-- Looking for pthread_np.h - not found
-- Performing Test HAVE_PTHREAD_SETNAME_NP
-- Performing Test HAVE_PTHREAD_SETNAME_NP - Success
-- Looking for clock_gettime in c
-- Looking for clock_gettime in c - found
-- Performing Test HAVE_POSIX_SPAWN
-- Performing Test HAVE_POSIX_SPAWN - Success
-- Looking for vfork
-- Looking for vfork - found

Please-just-dont avatar Dec 09 '25 15:12 Please-just-dont

I just compiled on an iMac Intel i5 8500, it's only from 2019, and it takes over 5 minutes to run through the above tests. I change one variable in CMake configuration, and I have to wait 5 minutes. It's pretty much unworkable on slower machines.

Edit: It only took 5 minutes on Xcode generator, which is really really slow for this. When I used Ninja it was more like 40 seconds.

Please-just-dont avatar Dec 09 '25 18:12 Please-just-dont

I'm gonna try an idea out, stay tuned.

icculus avatar Dec 09 '25 21:12 icculus

Okay, I ran with @maia-s's idea, but "fine-grained" isn't "string functions" but "ANSI C", "POSIX", "wcs* functions" and "Other Stuff" at the moment. Basically it tries to compile them all in one file, and if it works, marks them all as available. Otherwise it falls back to the usual way of checking to find them one by one.

This is not the most efficient way to do it, but it's definitely the simplest. Most efficient would be "let me check every symbol at once" and parse out the linker errors to see which failed...but that's error prone, probably.

diff --git a/CMakeLists.txt b/CMakeLists.txt
index b61f1b0b7..52252b06f 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1039,6 +1039,78 @@ if(MSVC)
   endif()
 endif()
 
+ macro(test_functions _SYMBOL_SET_NAME)
+  if(NOT CMAKE_REQUIRED_QUIET)
+    message(CHECK_START "Looking for symbol set '${_SYMBOL_SET_NAME}'")
+  endif()
+
+  set(_SYMBOL_SET ${ARGN})
+  set(SRCSTR "")
+  foreach(_FN IN LISTS _SYMBOL_SET)
+    #message(STATUS "SYMBOL ${_FN} ...")
+    string(APPEND SRCSTR "extern void ${_FN}(void);\n")
+  endforeach()
+  string(APPEND SRCSTR "int main(int argc, char **argv) { (void)argv;(void) argc;\n")
+  foreach(_FN IN LISTS _SYMBOL_SET)
+    string(APPEND SRCSTR "    ${_FN}();\n")
+  endforeach()
+  string(APPEND SRCSTR "}\n\n")
+
+  if(CMAKE_REQUIRED_LINK_OPTIONS)
+    set(CHECK_SYMBOL_EXISTS_LINK_OPTIONS
+      LINK_OPTIONS ${CMAKE_REQUIRED_LINK_OPTIONS})
+  else()
+    set(CHECK_SYMBOL_EXISTS_LINK_OPTIONS)
+  endif()
+  if(CMAKE_REQUIRED_LIBRARIES)
+    set(CHECK_SYMBOL_EXISTS_LIBS
+        LINK_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES})
+  else()
+    set(CHECK_SYMBOL_EXISTS_LIBS)
+  endif()
+  if(CMAKE_REQUIRED_INCLUDES)
+    set(CMAKE_SYMBOL_EXISTS_INCLUDES
+      "-DINCLUDE_DIRECTORIES:STRING=${CMAKE_REQUIRED_INCLUDES}")
+  else()
+    set(CMAKE_SYMBOL_EXISTS_INCLUDES)
+  endif()
+
+  #message(STATUS "${SRCSTR}")
+
+  try_compile(WHOLE_SET_IS_AVAILABLE
+      SOURCE_FROM_VAR "CheckMultipleFunctions.c" SRCSTR
+      COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS}
+      ${CHECK_SYMBOL_EXISTS_LINK_OPTIONS}
+      ${CHECK_SYMBOL_EXISTS_LIBS}
+      CMAKE_FLAGS
+      -DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_SYMBOL_EXISTS_FLAGS}
+      "${CMAKE_SYMBOL_EXISTS_INCLUDES}"
+  )
+
+  if(WHOLE_SET_IS_AVAILABLE)
+    if(NOT CMAKE_REQUIRED_QUIET)
+        message(CHECK_PASS "found")
+    endif()
+    foreach(_FN IN LISTS _SYMBOL_SET)
+      string(TOUPPER ${_FN} _UPPER)
+      #message(STATUS "HAVE_${_UPPER} TRUE")
+      set(HAVE_${_UPPER} 1)
+    endforeach()
+  else()
+    if(NOT CMAKE_REQUIRED_QUIET)
+        message(CHECK_FAIL "not found")
+     endif()
+    # Something wasn't available...Try them one at a time.
+    foreach(_FN IN LISTS _SYMBOL_SET)
+      string(TOUPPER ${_FN} _UPPER)
+      set(LIBC_HAS_VAR "LIBC_HAS_${_UPPER}")
+      check_symbol_exists("${_FN}" "${available_headers}" ${LIBC_HAS_VAR})
+      set(HAVE_${_UPPER} ${${LIBC_HAS_VAR}})
+      #message(STATUS "(HAVE_${_UPPER} ${${LIBC_HAS_VAR}}")
+    endforeach()
+  endif()
+endmacro()
+
 # TODO: Can't deactivate on FreeBSD? w/o LIBC, SDL_stdinc.h can't define anything.
 if(SDL_LIBC)
   set(available_headers)
@@ -1075,47 +1147,23 @@ if(SDL_LIBC)
     endif()
   endforeach()
 
-  set(symbols_to_check
-    abs acos acosf asin asinf atan atan2 atan2f atanf atof atoi
-    bcopy
-    ceil ceilf copysign copysignf cos cosf
-    _Exit exp expf
-    fabs fabsf floor floorf fmod fmodf fopen64 fseeko fseeko64
-    getenv
-    _i64toa index itoa
-    log log10 log10f logf lround lroundf _ltoa
-    malloc memcmp memcpy memmove memset modf modff
-    pow powf putenv
-    rindex round roundf
-    scalbn scalbnf setenv sin sinf sqr sqrt sqrtf sscanf strchr
-    strcmp strlcat strlcpy strlen strncmp strnlen strpbrk
-    strrchr strstr strnstr strtod strtok_r strtol strtoll strtoul strtoull
-    tan tanf trunc truncf
-    unsetenv
-    vsnprintf vsscanf
-    wcsnlen wcscmp wcsdup wcslcat wcslcpy wcslen wcsncmp wcsstr wcstol
-  )
-  if(WINDOWS)
-    list(APPEND symbols_to_check
-      _copysign _fseeki64 _strrev _ui64toa _uitoa _ultoa _wcsdup
-    )
-  else()
-    list(APPEND symbols_to_check
-        strcasestr
-    )
-  endif()
   check_library_exists(m pow "" HAVE_LIBM)
   cmake_push_check_state()
   if(HAVE_LIBM)
     sdl_link_dependency(math LIBS m)
     list(APPEND CMAKE_REQUIRED_LIBRARIES m)
   endif()
-  foreach(_FN IN LISTS symbols_to_check)
-    string(TOUPPER ${_FN} _UPPER)
-    set(LIBC_HAS_VAR "LIBC_HAS_${_UPPER}")
-    check_symbol_exists("${_FN}" "${available_headers}" ${LIBC_HAS_VAR})
-    set(HAVE_${_UPPER} ${${LIBC_HAS_VAR}})
-  endforeach()
+
+  test_functions("ANSI C" abs acos acosf asin asinf atan atan2 atan2f atanf atof atoi ceil ceilf copysign copysignf cos cosf exp expf fabs fabsf floor floorf getenv log log10 log10f logf lround lroundf malloc memcmp memcpy memmove memset pow powf putenv round roundf scalbn scalbnf setenv sin sinf sqrt sqrtf sscanf strchr strcmp strlcpy strlen strncmp strnlen strpbrk strrchr strstr tan tanf trunc truncf unsetenv vsnprintf vsscanf)
+  test_functions("POSIX" strtod strtok_r strtol strtoll strtoul strtoull modf modff fmod fmodf fseeko strcasestr)
+  test_functions("Wide String Functions" wcsnlen wcscmp wcsdup wcslcat wcslcpy wcslen wcsncmp wcsstr wcstol)
+  test_functions("Things Linux Doesn't Generally Have" strnstr itoa sqr)
+  test_functions("Other Stuff" fopen64 fseeko64 bcopy _Exit index rindex strlcat)
+
+  if(WINDOWS)
+    test_functions("MSVC LibC Stuff" _copysign _fseeki64 _strrev _ui64toa _uitoa _ultoa _ltoa _i64toa _wcsdup)
+  endif()
+
   cmake_pop_check_state()
 
   cmake_push_check_state()

This dropped the time on a cold cmake run in an empty directory from 28 seconds on my laptop to 15, and this was just for that one block of functions...there's lots of other things we check, too.

Also, this code is probably not great CMake code, so if this is a good idea, I'll leave it to someone else to clean it up or rewrite it from scratch.

icculus avatar Dec 10 '25 03:12 icculus

(Also it just pretends the functions are void fn(void); and tries to call them. We don't care, we just want to see if the linker will resolve the symbol, but this is a particular form of nasty, too.)

icculus avatar Dec 10 '25 03:12 icculus

Yay! @madebr, can you take a look?

slouken avatar Dec 10 '25 16:12 slouken

@icculus This is really cool. Thank you. You say:

(Also it just pretends the functions are void fn(void); and tries to call them. We don't care, we just want to see if the linker >will resolve the symbol, but this is a particular form of nasty, too.)

Won't the linker fail to link them if the signature is completely wrong? I don't get it.

Please-just-dont avatar Dec 10 '25 17:12 Please-just-dont

The linker is just looking for a symbol named "strcmp" and doesn't know anything else about it, so it works.

(In C++, function information is encoded in the symbol the linker sees, so it can resolve overloaded functions correctly: this is called "name mangling" and would have the problem you describe, but C doesn't have that.)

icculus avatar Dec 10 '25 20:12 icculus

I tested that approach earlier, but discarded it because it also detects symbols that are available in the libc library but not available in the headers, potentially causing compile errors later on. e. g. fopen64 and fseeko64 in glibc are conditionally declared in stdio.h if __USE_LARGEFILE64 is defined, but are available unconditionally in libc.so.6. strcasestr is also behaving weird in older gcc/clang.

I've experimented a bit with this at https://github.com/madebr/cmake-symbol-test. The potential time gains are immense, but there's some uncertainty. Its ci tests currently fail because of this "misalignment".

madebr avatar Dec 11 '25 03:12 madebr

Can someone explain why the generator selected (ie., Ninja/MSVC/XCode) makes an enormous difference to how long these tests take? I tried on macOS, and using the XCode generator it took over 5 minutes, whereas with Ninja it took about 40 seconds.

Please-just-dont avatar Dec 11 '25 08:12 Please-just-dont

Can someone explain why the generator selected (ie., Ninja/MSVC/XCode) makes an enormous difference to how long these tests take? I tried on macOS, and using the XCode generator it took over 5 minutes, whereas with Ninja it took about 40 seconds.

With make/Ninja, CMake launches Clang almost directly for every test. With Xcode, CMake generates a project for every test, and it builds this project via new instance of Xcode.

alexey-lysiuk avatar Dec 11 '25 08:12 alexey-lysiuk