SDL icon indicating copy to clipboard operation
SDL copied to clipboard

How to use prebuild config

Open amerkoleci opened this issue 1 year ago • 12 comments

Hi, Currently building SDL3 with CMake under Windows takes arround 9 minutes, most of time spent in configure part. Is there any way to make this step faster and use prebuild configurations (like: SDL_build_config_windows.h)

I've tried to dig the documentation and CMake file from root but didn't actually find the way.

Thanks in advance, Amer

amerkoleci avatar Mar 25 '24 08:03 amerkoleci

I see the following configure times:

Generator SDL_LIBC=ON SDL_LIBC=OFF
Ninja 144.9s 37.8s
Visual Studio 216.2s 46.5s

These times are comparable with the CI times (201.5s).

Are these similar with your system?

Relinquishing control to the include files is not really "the CMake way".

I prototyped the following completely independent script that parses the vcxproj projects. Copy it into VisualC/CMakeLists.txt, and use that instead.

VisualC/CMakeLists.txt
cmake_minimum_required(VERSION 3.5)
project(SDL3 LANGUAGES C CXX)

if(NOT WIN32 OR NOT MSVC)
    message(FATAL_ERROR "This CMake script only supports (non-UWP) Windows, using a MSVC compiler")
endif()

get_filename_component(SDL3_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/.." ABSOLUTE)

function(extract_vcxproj_sources SOURCES VCXPROJ_PATH)
    set(sources )
    get_filename_component(vcxproj_directory "${VCXPROJ_PATH}" DIRECTORY)
    file(READ "${VCXPROJ_PATH}" vcxproj_content)
    set(re_csource "<(ClCompile|ClInclude|ResourceCompile) Include=\"([.0-9a-zA-Z_\\]+)\"")
    string(REGEX MATCHALL "${re_csource}" cmatches "${vcxproj_content}")
    foreach(cmatch IN LISTS cmatches)
        string(REGEX MATCH "${re_csource}" _ "${cmatch}")
        file(TO_CMAKE_PATH "${CMAKE_MATCH_2}" csource)
        get_filename_component(csource "${csource}" ABSOLUTE BASE_DIR "${vcxproj_directory}")
        list(APPEND sources "${csource}")
    endforeach()
    if(NOT sources)
        message(FATAL_ERROR "Failed to extract sources from ${VCXPROJ_PATH}")
    endif()
    set(${SOURCES} ${sources} PARENT_SCOPE)
endfunction()

add_library(SDL3_Headers INTERFACE)
add_library(SDL3::Headers ALIAS SDL3_Headers)
target_include_directories(SDL3_Headers INTERFACE "$<BUILD_INTERFACE:${SDL3_ROOT}/include>")
target_include_directories(SDL3_Headers INTERFACE "$<BUILD_INTERFACE:${SDL3_ROOT}/include/SDL3>")

extract_vcxproj_sources(SDL_SOURCES "SDL/SDL.vcxproj")
add_library(SDL3-shared SHARED ${SDL_SOURCES})
add_library(SDL3::SDL3-shared ALIAS SDL3-shared)
add_library(SDL3::SDL3 ALIAS SDL3-shared)
target_compile_definitions(SDL3-shared PRIVATE DLL_EXPORT)
target_include_directories(SDL3-shared PRIVATE "${SDL3_ROOT}/include/build_config")
target_include_directories(SDL3-shared PRIVATE "${SDL3_ROOT}/src")
target_link_libraries(SDL3-shared PUBLIC SDL3::Headers)
target_link_libraries(SDL3-shared PRIVATE setupapi winmm imm32 version)
set_property(TARGET SDL3-shared PROPERTY PREFIX "")
set_property(TARGET SDL3-shared PROPERTY OUTPUT_NAME "SDL3")

include(CMakeDependentOption)

option(SDL_TEST_LIBRARY "Build SDL3_test library" OFF)
cmake_dependent_option(SDL_TESTS "Build SDL test executables" ON SDL_TEST_LIBRARY OFF)

if(SDL_TEST_LIBRARY)
    extract_vcxproj_sources(SDL_TEST_SOURCES "SDL_test/SDL_test.vcxproj")
    add_library(SDL3_test STATIC ${SDL_TEST_SOURCES})
    add_library(SDL3::SDL3_test ALIAS SDL3_test)
    target_link_libraries(SDL3_test PUBLIC SDL3::Headers)
    set_property(TARGET SDL3_test PROPERTY OUTPUT_NAME "SDL3_test")
endif()

if(SDL_TESTS)
    file(GLOB_RECURSE TEST_VCXPROJS "tests/*.vcxproj")
    foreach(test_vcxproj IN LISTS TEST_VCXPROJS)
        get_filename_component(testname "${test_vcxproj}" NAME_WE)
        extract_vcxproj_sources(TEST_SOURCES "${test_vcxproj}")
        add_executable(${testname} ${TEST_SOURCES})
        target_link_libraries(${testname} PRIVATE SDL3::SDL3_test SDL3::SDL3)
    endforeach()

    target_include_directories(testautomation PRIVATE "${SDL3_ROOT}/src")
endif()

Configure time drops to 5s since all compile tests have been eliminated.

madebr avatar Mar 25 '24 15:03 madebr

@slouken I see this warning when building SDL with the vcxproj-parsing cmake script:

C:\Users\maarten\source\repos\SDL\src\video\windows\SDL_windowsevents.c(751,103): warning C4267: 'func
tion': conversion from 'size_t' to 'DWORD', possible loss of data [C:\Users\maarten\source\repos\SDL\b
uild-mingw\SDL3-shared.vcxproj]

madebr avatar Mar 25 '24 16:03 madebr

@slouken I see this warning when building SDL with the vcxproj-parsing cmake script:

C:\Users\maarten\source\repos\SDL\src\video\windows\SDL_windowsevents.c(751,103): warning C4267: 'func
tion': conversion from 'size_t' to 'DWORD', possible loss of data [C:\Users\maarten\source\repos\SDL\b
uild-mingw\SDL3-shared.vcxproj]

Fixed, thanks!

BTW, I'll second my desire to have faster config times on Windows. It impacts me less because I do lots of iteration, but the initial cmake configuration step takes a really long time.

slouken avatar Mar 25 '24 18:03 slouken

configuration step takes a really long time.

Can all the libc checks be skipped under windows?

amerkoleci avatar Mar 25 '24 19:03 amerkoleci

configuration step takes a really long time.

Can all the libc checks be skipped under windows?

Only if you really really know what toolchain you're targeting, which the Visual Studio and Xcode projects do. The only configurability these offer is modification of the build_config headers.

Because the CMakeLists.txt should remain as platform-independent as possible, I think using the prebuilt config files is not a good direction. What we can do perhaps, is skip tests on MSVC by preseeding the cache. Those preseeded tests will then be skipped, improving configure time.

@slouken What is the minimum supported Visual Studio version? Can you configure SDL on this "old" version, and post the configure output + CMakeCache.txt here? This should probably also be repeated for all architectures, and for the latest supported VS2022. With those logs in hand, I can probably extract a minimum set of features MSVC supports.

madebr avatar Mar 25 '24 23:03 madebr

Sure, I can get those for you soon.

slouken avatar Mar 26 '24 00:03 slouken

What we can do perhaps, is skip tests on MSVC by preseeding the cache.

If that's possible, it would be a nice QoL change. In my current setup, the SDL3 configure phase alone takes more time than recompiling the whole code base. Most time is spent in "looking for {stdlib header}" checks, which also seem awfully slow for some weird reason.

code-disaster avatar Apr 11 '24 09:04 code-disaster

I've included the entire cmake configuration for x86 and x64 with Visual Studio 2015, 2017, 2019, and 2022: cmake-visual-studio.zip

slouken avatar Apr 16 '24 05:04 slouken

Thanks @slouken!

Can everybody here try #9570?

madebr avatar Apr 17 '24 19:04 madebr

A huge speedup, and seems to work for me just fine. I don't think pre-seeding the COMPILER_SUPPORTS_xxx flags works though. Not sure what's wrong, but it looks like CHECK_CPU_ARCHITECTURE_X64 is not set/true on the very first configure pass with a clean cache.

code-disaster avatar Apr 17 '24 20:04 code-disaster

A huge speedup, and seems to work for me just fine. I don't think pre-seeding the COMPILER_SUPPORTS_xxx flags works though. Not sure what's wrong, but it looks like CHECK_CPU_ARCHITECTURE_X64 is not set/true on the very first configure pass with a clean cache.

Makes sense! The preseeding should happen after detection of the architecture. It is an easy fix.

madebr avatar Apr 17 '24 21:04 madebr

I created a poc that detects headers and libc functions in parallel using the preprocessor and c++20. It can provide a big time gain, but the c++ code is effectively Undefined Behavior. It would be cool if a similar approach would get supported. It works on at least MSVC2017+ and gcc12+.

https://github.com/madebr/cmake-symbol-test Check the GitHub workflow logs to see the ci times.

madebr avatar Apr 25 '24 21:04 madebr

Makes sense! The preseeding should happen after detection of the architecture. It is an easy fix.

@madebr, have you already done this?

slouken avatar Oct 06 '24 18:10 slouken

Makes sense! The preseeding should happen after detection of the architecture. It is an easy fix.

@madebr, have you already done this?

Given we have x86, x64, arm32, arm64 and arm64ec with MSVC, I don't know how to detect this with 100% confidence.

Besides, since the creation of this issue, detection of the cpu architecture has been sped up a lot.

madebr avatar Oct 06 '24 18:10 madebr

Okay! I think we can close this then.

slouken avatar Oct 06 '24 19:10 slouken