|
| 1 | +cmake_minimum_required(VERSION 3.15) |
| 2 | +project(tinyfd VERSION 3.21.2 LANGUAGES C) |
| 3 | + |
| 4 | +# Options |
| 5 | +option(BUILD_SHARED_LIBS "Build tinyfd as shared library" ON) |
| 6 | +option(TINYFD_BUILD_EXAMPLES "Build example programs" OFF) |
| 7 | +option(TINYFD_BUILD_TESTS "Build test programs" OFF) |
| 8 | +option(TINYFD_INSTALL "Generate install targets" ON) |
| 9 | +option(TINYFD_ENABLE_WARNINGS "Enable extra compiler warnings" ON) |
| 10 | +option(TINYFD_ENABLE_OPTIMIZATIONS "Enable compiler optimizations (Release-like)" ON) |
| 11 | + |
| 12 | +# C standard |
| 13 | +set(CMAKE_C_STANDARD 11) |
| 14 | +set(CMAKE_C_STANDARD_REQUIRED ON) |
| 15 | +set(CMAKE_C_EXTENSIONS OFF) |
| 16 | + |
| 17 | +# Output directories |
| 18 | +# Put runtime artifacts and libraries into the build tree under bin/ and lib/ |
| 19 | +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin") |
| 20 | +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib") |
| 21 | +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib") |
| 22 | + |
| 23 | +# Source and include directory variables (default to project directory) |
| 24 | +set(TINYFD_SRC_DIR "${CMAKE_CURRENT_SOURCE_DIR}" CACHE PATH "Directory containing tinyfd source files") |
| 25 | +set(TINYFD_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}" CACHE PATH "Directory containing tinyfd header files") |
| 26 | + |
| 27 | +# Prefer conventional src/ and include/ subdirectories if they exist |
| 28 | +if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/src") |
| 29 | + set(TINYFD_SRC_DIR "${CMAKE_CURRENT_SOURCE_DIR}/src" CACHE PATH "Directory containing tinyfd source files" FORCE) |
| 30 | +endif() |
| 31 | +if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/include") |
| 32 | + set(TINYFD_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/include" CACHE PATH "Directory containing tinyfd header files" FORCE) |
| 33 | +endif() |
| 34 | + |
| 35 | +# Require an explicit semicolon-separated list of source files. |
| 36 | +# Do NOT use globbing or auto-discovery. Provide paths relative to the |
| 37 | +# project root or absolute paths. Example: -DTINYFD_SOURCE_FILES="src/a.c;src/b.c" |
| 38 | +set(TINYFD_SOURCE_FILES "tinyfiledialogs.c" CACHE STRING "Semicolon-separated list of source files for tinyfd (required).") |
| 39 | + |
| 40 | +# Fail early if the user didn't provide any source files — no auto-discovery allowed. |
| 41 | +if(NOT TINYFD_SOURCE_FILES) |
| 42 | + message(FATAL_ERROR "TINYFD_SOURCE_FILES is empty. Please set it to a semicolon-separated list of source files (no GLOB_RECURSE or discovery).") |
| 43 | +endif() |
| 44 | + |
| 45 | +# Convert the semicolon-separated cache string into a CMake list and validate files. |
| 46 | +# Convert the semicolon-separated cache string into a CMake list and resolve |
| 47 | +# each entry to an absolute path (relative paths are resolved against the |
| 48 | +# project source directory). Validate existence and build the final list. |
| 49 | +set(TINYFD_SOURCE_LIST ${TINYFD_SOURCE_FILES}) |
| 50 | +set(TINYFD_SOURCES "") |
| 51 | +foreach(_src IN LISTS TINYFD_SOURCE_LIST) |
| 52 | + if(NOT IS_ABSOLUTE "${_src}") |
| 53 | + set(_abs_src "${CMAKE_CURRENT_SOURCE_DIR}/${_src}") |
| 54 | + else() |
| 55 | + set(_abs_src "${_src}") |
| 56 | + endif() |
| 57 | + |
| 58 | + if(NOT EXISTS "${_abs_src}") |
| 59 | + message(FATAL_ERROR "Source file '${_src}' (resolved to '${_abs_src}') listed in TINYFD_SOURCE_FILES does not exist.") |
| 60 | + endif() |
| 61 | + |
| 62 | + list(APPEND TINYFD_SOURCES "${_abs_src}") |
| 63 | +endforeach() |
| 64 | + |
| 65 | +add_library(tinyfd ${TINYFD_SOURCES}) |
| 66 | + |
| 67 | + target_include_directories(tinyfd PUBLIC |
| 68 | + $<BUILD_INTERFACE:${TINYFD_INCLUDE_DIR}> |
| 69 | + $<INSTALL_INTERFACE:include> |
| 70 | + ) |
| 71 | + |
| 72 | + if(TINYFD_ENABLE_WARNINGS) |
| 73 | + if(MSVC) |
| 74 | + target_compile_options(tinyfd PRIVATE /W4 /permissive-) |
| 75 | + else() |
| 76 | + target_compile_options(tinyfd PRIVATE -Wall -Wextra -Wpedantic) |
| 77 | + endif() |
| 78 | + endif() |
| 79 | + |
| 80 | + # Enable optimizations when requested and only for Release-like configurations. |
| 81 | + # This supports both single-config generators (checks CMAKE_BUILD_TYPE) and |
| 82 | + # multi-config generators via generator expressions ($<CONFIG:...>). |
| 83 | + if(TINYFD_ENABLE_OPTIMIZATIONS) |
| 84 | + # Helper generator expressions for config-aware flags |
| 85 | + if(MSVC) |
| 86 | + # Apply /O2 for Release and RelWithDebInfo |
| 87 | + target_compile_options(tinyfd PRIVATE |
| 88 | + $<$<OR:$<CONFIG:Release>,$<CONFIG:RelWithDebInfo>>:/O2> |
| 89 | + ) |
| 90 | + # For single-config generators, also respect CMAKE_BUILD_TYPE variable |
| 91 | + if(NOT CMAKE_CONFIGURATION_TYPES) |
| 92 | + if(CMAKE_BUILD_TYPE STREQUAL "Release" OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo") |
| 93 | + string(APPEND CMAKE_C_FLAGS " /O2") |
| 94 | + endif() |
| 95 | + endif() |
| 96 | + else() |
| 97 | + # Apply -O3 (and optionally -flto) for Release and RelWithDebInfo |
| 98 | + target_compile_options(tinyfd PRIVATE |
| 99 | + $<$<OR:$<CONFIG:Release>,$<CONFIG:RelWithDebInfo>>:-O3> |
| 100 | + ) |
| 101 | + |
| 102 | + # Check for -flto support and add it in a config-aware manner |
| 103 | + include(CheckCCompilerFlag) |
| 104 | + check_c_compiler_flag("-flto" COMPILER_SUPPORTS_FLTO) |
| 105 | + if(COMPILER_SUPPORTS_FLTO) |
| 106 | + target_compile_options(tinyfd PRIVATE |
| 107 | + $<$<OR:$<CONFIG:Release>,$<CONFIG:RelWithDebInfo>>:-flto> |
| 108 | + ) |
| 109 | + endif() |
| 110 | + |
| 111 | + # Single-config fallback: if using a single-config generator and the |
| 112 | + # build type is a release-like type, append flags to CMAKE_C_FLAGS |
| 113 | + if(NOT CMAKE_CONFIGURATION_TYPES) |
| 114 | + if(CMAKE_BUILD_TYPE STREQUAL "Release" OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo") |
| 115 | + string(APPEND CMAKE_C_FLAGS " -O3") |
| 116 | + if(COMPILER_SUPPORTS_FLTO) |
| 117 | + string(APPEND CMAKE_C_FLAGS " -flto") |
| 118 | + endif() |
| 119 | + endif() |
| 120 | + endif() |
| 121 | + endif() |
| 122 | + endif() |
| 123 | + |
| 124 | + if(TINYFD_INSTALL) |
| 125 | + install(TARGETS tinyfd |
| 126 | + EXPORT tinyfdTargets |
| 127 | + ARCHIVE DESTINATION lib |
| 128 | + LIBRARY DESTINATION lib |
| 129 | + RUNTIME DESTINATION bin) |
| 130 | + # Install headers from the configured include directory |
| 131 | + install(DIRECTORY "${TINYFD_INCLUDE_DIR}/" DESTINATION include) |
| 132 | + install(EXPORT tinyfdTargets FILE tinyfdTargets.cmake NAMESPACE tinyfd:: DESTINATION lib/cmake/tinyfd) |
| 133 | + endif() |
| 134 | + |
| 135 | +# Optional subdirectories |
| 136 | +if(TINYFD_BUILD_EXAMPLES) |
| 137 | + add_subdirectory(examples) |
| 138 | +endif() |
| 139 | + |
| 140 | +if(TINYFD_BUILD_TESTS) |
| 141 | + enable_testing() |
| 142 | + add_subdirectory(tests) |
| 143 | +endif() |
0 commit comments