duckstation

duckstation, but archived from the revision just before upstream changed it to a proprietary software project, this version is the libre one
git clone https://git.neptards.moe/u3shit/duckstation.git
Log | Files | Refs | README | LICENSE

CMakeLists.txt (16278B)


      1 cmake_minimum_required(VERSION 3.8...3.26)
      2 
      3 # Fallback for using newer policies on CMake <3.12.
      4 if(${CMAKE_VERSION} VERSION_LESS 3.12)
      5   cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
      6 endif()
      7 
      8 # Determine if fmt is built as a subproject (using add_subdirectory)
      9 # or if it is the master project.
     10 if (NOT DEFINED FMT_MASTER_PROJECT)
     11   set(FMT_MASTER_PROJECT OFF)
     12   if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
     13     set(FMT_MASTER_PROJECT ON)
     14     message(STATUS "CMake version: ${CMAKE_VERSION}")
     15   endif ()
     16 endif ()
     17 
     18 # Joins arguments and places the results in ${result_var}.
     19 function(join result_var)
     20   set(result "")
     21   foreach (arg ${ARGN})
     22     set(result "${result}${arg}")
     23   endforeach ()
     24   set(${result_var} "${result}" PARENT_SCOPE)
     25 endfunction()
     26 
     27 # DEPRECATED! Should be merged into add_module_library.
     28 function(enable_module target)
     29   if (MSVC)
     30     set(BMI ${CMAKE_CURRENT_BINARY_DIR}/${target}.ifc)
     31     target_compile_options(${target}
     32       PRIVATE /interface /ifcOutput ${BMI}
     33       INTERFACE /reference fmt=${BMI})
     34     set_target_properties(${target} PROPERTIES ADDITIONAL_CLEAN_FILES ${BMI})
     35     set_source_files_properties(${BMI} PROPERTIES GENERATED ON)
     36   endif ()
     37 endfunction()
     38 
     39 # Adds a library compiled with C++20 module support.
     40 # `enabled` is a CMake variables that specifies if modules are enabled.
     41 # If modules are disabled `add_module_library` falls back to creating a
     42 # non-modular library.
     43 #
     44 # Usage:
     45 #   add_module_library(<name> [sources...] FALLBACK [sources...] [IF enabled])
     46 function(add_module_library name)
     47   cmake_parse_arguments(AML "" "IF" "FALLBACK" ${ARGN})
     48   set(sources ${AML_UNPARSED_ARGUMENTS})
     49 
     50   add_library(${name})
     51   set_target_properties(${name} PROPERTIES LINKER_LANGUAGE CXX)
     52 
     53   if (NOT ${${AML_IF}})
     54     # Create a non-modular library.
     55     target_sources(${name} PRIVATE ${AML_FALLBACK})
     56     return()
     57   endif ()
     58 
     59   # Modules require C++20.
     60   target_compile_features(${name} PUBLIC cxx_std_20)
     61   if (CMAKE_COMPILER_IS_GNUCXX)
     62     target_compile_options(${name} PUBLIC -fmodules-ts)
     63   endif ()
     64 
     65   # `std` is affected by CMake options and may be higher than C++20.
     66   get_target_property(std ${name} CXX_STANDARD)
     67 
     68   if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
     69     set(pcms)
     70     foreach (src ${sources})
     71       get_filename_component(pcm ${src} NAME_WE)
     72       set(pcm ${pcm}.pcm)
     73 
     74       # Propagate -fmodule-file=*.pcm to targets that link with this library.
     75       target_compile_options(
     76         ${name} PUBLIC -fmodule-file=${CMAKE_CURRENT_BINARY_DIR}/${pcm})
     77 
     78       # Use an absolute path to prevent target_link_libraries prepending -l
     79       # to it.
     80       set(pcms ${pcms} ${CMAKE_CURRENT_BINARY_DIR}/${pcm})
     81       add_custom_command(
     82         OUTPUT ${pcm}
     83         COMMAND ${CMAKE_CXX_COMPILER}
     84                 -std=c++${std} -x c++-module --precompile -c
     85                 -o ${pcm} ${CMAKE_CURRENT_SOURCE_DIR}/${src}
     86                 "-I$<JOIN:$<TARGET_PROPERTY:${name},INCLUDE_DIRECTORIES>,;-I>"
     87         # Required by the -I generator expression above.
     88         COMMAND_EXPAND_LISTS
     89         DEPENDS ${src})
     90     endforeach ()
     91 
     92     # Add .pcm files as sources to make sure they are built before the library.
     93     set(sources)
     94     foreach (pcm ${pcms})
     95       get_filename_component(pcm_we ${pcm} NAME_WE)
     96       set(obj ${pcm_we}.o)
     97       # Use an absolute path to prevent target_link_libraries prepending -l.
     98       set(sources ${sources} ${pcm} ${CMAKE_CURRENT_BINARY_DIR}/${obj})
     99       add_custom_command(
    100         OUTPUT ${obj}
    101         COMMAND ${CMAKE_CXX_COMPILER} $<TARGET_PROPERTY:${name},COMPILE_OPTIONS>
    102                 -c -o ${obj} ${pcm}
    103         DEPENDS ${pcm})
    104     endforeach ()
    105   endif ()
    106   target_sources(${name} PRIVATE ${sources})
    107 endfunction()
    108 
    109 include(CMakeParseArguments)
    110 
    111 # Sets a cache variable with a docstring joined from multiple arguments:
    112 #   set(<variable> <value>... CACHE <type> <docstring>...)
    113 # This allows splitting a long docstring for readability.
    114 function(set_verbose)
    115   # cmake_parse_arguments is broken in CMake 3.4 (cannot parse CACHE) so use
    116   # list instead.
    117   list(GET ARGN 0 var)
    118   list(REMOVE_AT ARGN 0)
    119   list(GET ARGN 0 val)
    120   list(REMOVE_AT ARGN 0)
    121   list(REMOVE_AT ARGN 0)
    122   list(GET ARGN 0 type)
    123   list(REMOVE_AT ARGN 0)
    124   join(doc ${ARGN})
    125   set(${var} ${val} CACHE ${type} ${doc})
    126 endfunction()
    127 
    128 # Set the default CMAKE_BUILD_TYPE to Release.
    129 # This should be done before the project command since the latter can set
    130 # CMAKE_BUILD_TYPE itself (it does so for nmake).
    131 if (FMT_MASTER_PROJECT AND NOT CMAKE_BUILD_TYPE)
    132   set_verbose(CMAKE_BUILD_TYPE Release CACHE STRING
    133               "Choose the type of build, options are: None(CMAKE_CXX_FLAGS or "
    134               "CMAKE_C_FLAGS used) Debug Release RelWithDebInfo MinSizeRel.")
    135 endif ()
    136 
    137 project(FMT CXX)
    138 include(GNUInstallDirs)
    139 set_verbose(FMT_INC_DIR ${CMAKE_INSTALL_INCLUDEDIR} CACHE STRING
    140             "Installation directory for include files, a relative path that "
    141             "will be joined with ${CMAKE_INSTALL_PREFIX} or an absolute path.")
    142 
    143 option(FMT_PEDANTIC "Enable extra warnings and expensive tests." OFF)
    144 option(FMT_WERROR "Halt the compilation with an error on compiler warnings."
    145        OFF)
    146 
    147 # Options that control generation of various targets.
    148 option(FMT_DOC "Generate the doc target." ${FMT_MASTER_PROJECT})
    149 option(FMT_INSTALL "Generate the install target." ON)
    150 option(FMT_TEST "Generate the test target." ${FMT_MASTER_PROJECT})
    151 option(FMT_FUZZ "Generate the fuzz target." OFF)
    152 option(FMT_CUDA_TEST "Generate the cuda-test target." OFF)
    153 option(FMT_OS "Include core requiring OS (Windows/Posix) " ON)
    154 option(FMT_MODULE "Build a module instead of a traditional library." OFF)
    155 option(FMT_SYSTEM_HEADERS "Expose headers with marking them as system." OFF)
    156 
    157 if (FMT_TEST AND FMT_MODULE)
    158   # The tests require {fmt} to be compiled as traditional library
    159   message(STATUS "Testing is incompatible with build mode 'module'.")
    160 endif ()
    161 set(FMT_SYSTEM_HEADERS_ATTRIBUTE "")
    162 if (FMT_SYSTEM_HEADERS)
    163   set(FMT_SYSTEM_HEADERS_ATTRIBUTE SYSTEM)
    164 endif ()
    165 if(CMAKE_SYSTEM_NAME STREQUAL "MSDOS")
    166   set(FMT_TEST OFF)
    167   message(STATUS "MSDOS is incompatible with gtest")
    168 endif()
    169 
    170 # Get version from core.h
    171 file(READ include/fmt/core.h core_h)
    172 if (NOT core_h MATCHES "FMT_VERSION ([0-9]+)([0-9][0-9])([0-9][0-9])")
    173   message(FATAL_ERROR "Cannot get FMT_VERSION from core.h.")
    174 endif ()
    175 # Use math to skip leading zeros if any.
    176 math(EXPR CPACK_PACKAGE_VERSION_MAJOR ${CMAKE_MATCH_1})
    177 math(EXPR CPACK_PACKAGE_VERSION_MINOR ${CMAKE_MATCH_2})
    178 math(EXPR CPACK_PACKAGE_VERSION_PATCH ${CMAKE_MATCH_3})
    179 join(FMT_VERSION ${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.
    180                  ${CPACK_PACKAGE_VERSION_PATCH})
    181 message(STATUS "Version: ${FMT_VERSION}")
    182 
    183 message(STATUS "Build type: ${CMAKE_BUILD_TYPE}")
    184 
    185 if (NOT CMAKE_RUNTIME_OUTPUT_DIRECTORY)
    186   set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/bin)
    187 endif ()
    188 
    189 set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH}
    190   "${CMAKE_CURRENT_SOURCE_DIR}/support/cmake")
    191 
    192 include(CheckCXXCompilerFlag)
    193 include(JoinPaths)
    194 
    195 if (FMT_MASTER_PROJECT AND NOT DEFINED CMAKE_CXX_VISIBILITY_PRESET)
    196   set_verbose(CMAKE_CXX_VISIBILITY_PRESET hidden CACHE STRING
    197               "Preset for the export of private symbols")
    198   set_property(CACHE CMAKE_CXX_VISIBILITY_PRESET PROPERTY STRINGS
    199                hidden default)
    200 endif ()
    201 
    202 if (FMT_MASTER_PROJECT AND NOT DEFINED CMAKE_VISIBILITY_INLINES_HIDDEN)
    203   set_verbose(CMAKE_VISIBILITY_INLINES_HIDDEN ON CACHE BOOL
    204               "Whether to add a compile flag to hide symbols of inline functions")
    205 endif ()
    206 
    207 if (CMAKE_CXX_COMPILER_ID MATCHES "GNU")
    208   set(PEDANTIC_COMPILE_FLAGS -pedantic-errors -Wall -Wextra -pedantic
    209       -Wold-style-cast -Wundef
    210       -Wredundant-decls -Wwrite-strings -Wpointer-arith
    211       -Wcast-qual -Wformat=2 -Wmissing-include-dirs
    212       -Wcast-align
    213       -Wctor-dtor-privacy -Wdisabled-optimization
    214       -Winvalid-pch -Woverloaded-virtual
    215       -Wconversion -Wundef
    216       -Wno-ctor-dtor-privacy -Wno-format-nonliteral)
    217   if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.6)
    218       set(PEDANTIC_COMPILE_FLAGS ${PEDANTIC_COMPILE_FLAGS}
    219          -Wno-dangling-else -Wno-unused-local-typedefs)
    220   endif ()
    221   if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.0)
    222       set(PEDANTIC_COMPILE_FLAGS ${PEDANTIC_COMPILE_FLAGS} -Wdouble-promotion
    223           -Wtrampolines -Wzero-as-null-pointer-constant -Wuseless-cast
    224           -Wvector-operation-performance -Wsized-deallocation -Wshadow)
    225   endif ()
    226   if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 6.0)
    227       set(PEDANTIC_COMPILE_FLAGS ${PEDANTIC_COMPILE_FLAGS} -Wshift-overflow=2
    228           -Wnull-dereference -Wduplicated-cond)
    229   endif ()
    230   set(WERROR_FLAG -Werror)
    231 endif ()
    232 
    233 if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
    234   set(PEDANTIC_COMPILE_FLAGS -Wall -Wextra -pedantic -Wconversion -Wundef
    235       -Wdeprecated -Wweak-vtables -Wshadow
    236       -Wno-gnu-zero-variadic-macro-arguments)
    237   check_cxx_compiler_flag(-Wzero-as-null-pointer-constant HAS_NULLPTR_WARNING)
    238   if (HAS_NULLPTR_WARNING)
    239     set(PEDANTIC_COMPILE_FLAGS ${PEDANTIC_COMPILE_FLAGS}
    240         -Wzero-as-null-pointer-constant)
    241   endif ()
    242   set(WERROR_FLAG -Werror)
    243 endif ()
    244 
    245 if (MSVC)
    246   set(PEDANTIC_COMPILE_FLAGS /W3)
    247   set(WERROR_FLAG /WX)
    248 endif ()
    249 
    250 if (FMT_MASTER_PROJECT AND CMAKE_GENERATOR MATCHES "Visual Studio")
    251   # If Microsoft SDK is installed create script run-msbuild.bat that
    252   # calls SetEnv.cmd to set up build environment and runs msbuild.
    253   # It is useful when building Visual Studio projects with the SDK
    254   # toolchain rather than Visual Studio.
    255   include(FindSetEnv)
    256   if (WINSDK_SETENV)
    257     set(MSBUILD_SETUP "call \"${WINSDK_SETENV}\"")
    258   endif ()
    259   # Set FrameworkPathOverride to get rid of MSB3644 warnings.
    260   join(netfxpath
    261        "C:\\Program Files\\Reference Assemblies\\Microsoft\\Framework\\"
    262        ".NETFramework\\v4.0")
    263   file(WRITE run-msbuild.bat "
    264     ${MSBUILD_SETUP}
    265     ${CMAKE_MAKE_PROGRAM} -p:FrameworkPathOverride=\"${netfxpath}\" %*")
    266 endif ()
    267 
    268 function(add_headers VAR)
    269   set(headers ${${VAR}})
    270   foreach (header ${ARGN})
    271     set(headers ${headers} include/fmt/${header})
    272   endforeach()
    273   set(${VAR} ${headers} PARENT_SCOPE)
    274 endfunction()
    275 
    276 # Define the fmt library, its includes and the needed defines.
    277 add_headers(FMT_HEADERS args.h chrono.h color.h compile.h core.h format.h
    278                         format-inl.h os.h ostream.h printf.h ranges.h std.h
    279                         xchar.h)
    280 set(FMT_SOURCES src/format.cc)
    281 if (FMT_OS)
    282   set(FMT_SOURCES ${FMT_SOURCES} src/os.cc)
    283 endif ()
    284 
    285 add_module_library(fmt src/fmt.cc FALLBACK
    286                    ${FMT_SOURCES} ${FMT_HEADERS} README.rst ChangeLog.rst
    287                    IF FMT_MODULE)
    288 add_library(fmt::fmt ALIAS fmt)
    289 if (FMT_MODULE)
    290   enable_module(fmt)
    291 endif ()
    292 
    293 if (FMT_WERROR)
    294   target_compile_options(fmt PRIVATE ${WERROR_FLAG})
    295 endif ()
    296 if (FMT_PEDANTIC)
    297   target_compile_options(fmt PRIVATE ${PEDANTIC_COMPILE_FLAGS})
    298 endif ()
    299 
    300 if (cxx_std_11 IN_LIST CMAKE_CXX_COMPILE_FEATURES)
    301   target_compile_features(fmt PUBLIC cxx_std_11)
    302 else ()
    303   message(WARNING "Feature cxx_std_11 is unknown for the CXX compiler")
    304 endif ()
    305 
    306 target_include_directories(fmt ${FMT_SYSTEM_HEADERS_ATTRIBUTE} PUBLIC
    307   $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
    308   $<INSTALL_INTERFACE:${FMT_INC_DIR}>)
    309 
    310 set(FMT_DEBUG_POSTFIX d CACHE STRING "Debug library postfix.")
    311 
    312 set_target_properties(fmt PROPERTIES
    313   VERSION ${FMT_VERSION} SOVERSION ${CPACK_PACKAGE_VERSION_MAJOR}
    314   PUBLIC_HEADER "${FMT_HEADERS}"
    315   DEBUG_POSTFIX "${FMT_DEBUG_POSTFIX}")
    316 
    317 # Set FMT_LIB_NAME for pkg-config fmt.pc. We cannot use the OUTPUT_NAME target
    318 # property because it's not set by default.
    319 set(FMT_LIB_NAME fmt)
    320 if (CMAKE_BUILD_TYPE STREQUAL "Debug")
    321   set(FMT_LIB_NAME ${FMT_LIB_NAME}${FMT_DEBUG_POSTFIX})
    322 endif ()
    323 
    324 if (BUILD_SHARED_LIBS)
    325   target_compile_definitions(fmt PRIVATE FMT_LIB_EXPORT INTERFACE FMT_SHARED)
    326 endif ()
    327 if (FMT_SAFE_DURATION_CAST)
    328   target_compile_definitions(fmt PUBLIC FMT_SAFE_DURATION_CAST)
    329 endif()
    330 
    331 add_library(fmt-header-only INTERFACE)
    332 add_library(fmt::fmt-header-only ALIAS fmt-header-only)
    333 
    334 target_compile_definitions(fmt-header-only INTERFACE FMT_HEADER_ONLY=1)
    335 target_compile_features(fmt-header-only INTERFACE cxx_std_11)
    336 
    337 target_include_directories(fmt-header-only ${FMT_SYSTEM_HEADERS_ATTRIBUTE} INTERFACE
    338   $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
    339   $<INSTALL_INTERFACE:${FMT_INC_DIR}>)
    340 
    341 # Install targets.
    342 if (FMT_INSTALL)
    343   include(CMakePackageConfigHelpers)
    344   set_verbose(FMT_CMAKE_DIR ${CMAKE_INSTALL_LIBDIR}/cmake/fmt CACHE STRING
    345               "Installation directory for cmake files, a relative path that "
    346               "will be joined with ${CMAKE_INSTALL_PREFIX} or an absolute "
    347               "path.")
    348   set(version_config ${PROJECT_BINARY_DIR}/fmt-config-version.cmake)
    349   set(project_config ${PROJECT_BINARY_DIR}/fmt-config.cmake)
    350   set(pkgconfig ${PROJECT_BINARY_DIR}/fmt.pc)
    351   set(targets_export_name fmt-targets)
    352 
    353   set_verbose(FMT_LIB_DIR ${CMAKE_INSTALL_LIBDIR} CACHE STRING
    354               "Installation directory for libraries, a relative path that "
    355               "will be joined to ${CMAKE_INSTALL_PREFIX} or an absolute path.")
    356 
    357   set_verbose(FMT_PKGCONFIG_DIR ${CMAKE_INSTALL_LIBDIR}/pkgconfig CACHE STRING
    358               "Installation directory for pkgconfig (.pc) files, a relative "
    359               "path that will be joined with ${CMAKE_INSTALL_PREFIX} or an "
    360               "absolute path.")
    361 
    362   # Generate the version, config and target files into the build directory.
    363   write_basic_package_version_file(
    364     ${version_config}
    365     VERSION ${FMT_VERSION}
    366     COMPATIBILITY AnyNewerVersion)
    367 
    368   join_paths(libdir_for_pc_file "\${exec_prefix}" "${FMT_LIB_DIR}")
    369   join_paths(includedir_for_pc_file "\${prefix}" "${FMT_INC_DIR}")
    370 
    371   configure_file(
    372     "${PROJECT_SOURCE_DIR}/support/cmake/fmt.pc.in"
    373     "${pkgconfig}"
    374     @ONLY)
    375   configure_package_config_file(
    376     ${PROJECT_SOURCE_DIR}/support/cmake/fmt-config.cmake.in
    377     ${project_config}
    378     INSTALL_DESTINATION ${FMT_CMAKE_DIR})
    379 
    380   set(INSTALL_TARGETS fmt fmt-header-only)
    381 
    382   # Install the library and headers.
    383   install(TARGETS ${INSTALL_TARGETS} EXPORT ${targets_export_name}
    384           LIBRARY DESTINATION ${FMT_LIB_DIR}
    385           ARCHIVE DESTINATION ${FMT_LIB_DIR}
    386           PUBLIC_HEADER DESTINATION "${FMT_INC_DIR}/fmt"
    387           RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
    388 
    389   # Use a namespace because CMake provides better diagnostics for namespaced
    390   # imported targets.
    391   export(TARGETS ${INSTALL_TARGETS} NAMESPACE fmt::
    392          FILE ${PROJECT_BINARY_DIR}/${targets_export_name}.cmake)
    393 
    394   # Install version, config and target files.
    395   install(
    396     FILES ${project_config} ${version_config}
    397     DESTINATION ${FMT_CMAKE_DIR})
    398   install(EXPORT ${targets_export_name} DESTINATION ${FMT_CMAKE_DIR}
    399           NAMESPACE fmt::)
    400 
    401   install(FILES "${pkgconfig}" DESTINATION "${FMT_PKGCONFIG_DIR}")
    402 endif ()
    403 
    404 if (FMT_DOC)
    405   add_subdirectory(doc)
    406 endif ()
    407 
    408 if (FMT_TEST)
    409   enable_testing()
    410   add_subdirectory(test)
    411 endif ()
    412 
    413 # Control fuzzing independent of the unit tests.
    414 if (FMT_FUZZ)
    415   add_subdirectory(test/fuzzing)
    416 
    417   # The FMT_FUZZ macro is used to prevent resource exhaustion in fuzzing
    418   # mode and make fuzzing practically possible. It is similar to
    419   # FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION but uses a different name to
    420   # avoid interfering with fuzzing of projects that use {fmt}.
    421   # See also https://llvm.org/docs/LibFuzzer.html#fuzzer-friendly-build-mode.
    422   target_compile_definitions(fmt PUBLIC FMT_FUZZ)
    423 endif ()
    424 
    425 set(gitignore ${PROJECT_SOURCE_DIR}/.gitignore)
    426 if (FMT_MASTER_PROJECT AND EXISTS ${gitignore})
    427   # Get the list of ignored files from .gitignore.
    428   file (STRINGS ${gitignore} lines)
    429   list(REMOVE_ITEM lines /doc/html)
    430   foreach (line ${lines})
    431     string(REPLACE "." "[.]" line "${line}")
    432     string(REPLACE "*" ".*" line "${line}")
    433     set(ignored_files ${ignored_files} "${line}$" "${line}/")
    434   endforeach ()
    435   set(ignored_files ${ignored_files}
    436     /.git /breathe /format-benchmark sphinx/ .buildinfo .doctrees)
    437 
    438   set(CPACK_SOURCE_GENERATOR ZIP)
    439   set(CPACK_SOURCE_IGNORE_FILES ${ignored_files})
    440   set(CPACK_SOURCE_PACKAGE_FILE_NAME fmt-${FMT_VERSION})
    441   set(CPACK_PACKAGE_NAME fmt)
    442   set(CPACK_RESOURCE_FILE_README ${PROJECT_SOURCE_DIR}/README.rst)
    443   include(CPack)
    444 endif ()