diff options
507 files changed, 8469 insertions, 6016 deletions
diff --git a/.codespellrc b/.codespellrc index a8be487..0abd94e 100644 --- a/.codespellrc +++ b/.codespellrc @@ -1,7 +1,6 @@ [codespell] check-filenames = check-hidden = -count = # Disable warnings about binary files quiet-level = 2 builtin = clear,rare,en-GB_to_en-US @@ -1,27 +1,30 @@ +/CMakeUserPresets.json + # Common build directories -build*/ +/build*/ -# Exclude MacOS Finder files. +# MacOS Finder files. .DS_Store -*.user* - +# Python compile output. *.pyc -Help/_generated -Testing -CMakeUserPresets.json +# See Utilities/Sphinx/tutorial_archive.cmake +/Help/_generated -# Visual Studio work directory -.vs/ -# Visual Studio build directory -out/ +# CLion work directory +/.idea/ +# CLion build directories +/cmake-build-*/ + +# QtCreator files. +/CMakeLists.txt.user* # Visual Studio Code -.vscode/ -.cache/ +/.vscode/ +/.cache/ -# CLion work directory -.idea/ -# CLion build directories -cmake-build-*/ +# Visual Studio work directory +/.vs/ +# Visual Studio build directory +/out/ diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 829e34f..2c81b37 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1104,7 +1104,7 @@ t:windows-borland5.8: variables: CMAKE_CI_JOB_NIGHTLY: "true" -t:windows-clang15.0-cl-ninja: +t:windows-clang16.0-cl-ninja: extends: - .windows_clang_ninja - .cmake_test_windows_external @@ -1116,10 +1116,10 @@ t:windows-clang15.0-cl-ninja: needs: - t:windows-vs2022-x64-ninja variables: - CMAKE_CI_BUILD_NAME: windows_clang15.0_cl_ninja + CMAKE_CI_BUILD_NAME: windows_clang16.0_cl_ninja CMAKE_CI_JOB_NIGHTLY: "true" -t:windows-clang15.0-cl-nmake: +t:windows-clang16.0-cl-nmake: extends: - .windows_clang_nmake - .cmake_test_windows_external @@ -1131,10 +1131,10 @@ t:windows-clang15.0-cl-nmake: needs: - t:windows-vs2022-x64-ninja variables: - CMAKE_CI_BUILD_NAME: windows_clang15.0_cl_nmake + CMAKE_CI_BUILD_NAME: windows_clang16.0_cl_nmake CMAKE_CI_JOB_NIGHTLY: "true" -t:windows-clang15.0-gnu-ninja: +t:windows-clang16.0-gnu-ninja: extends: - .windows_clang_ninja - .cmake_test_windows_external @@ -1146,10 +1146,10 @@ t:windows-clang15.0-gnu-ninja: needs: - t:windows-vs2022-x64-ninja variables: - CMAKE_CI_BUILD_NAME: windows_clang15.0_gnu_ninja + CMAKE_CI_BUILD_NAME: windows_clang16.0_gnu_ninja CMAKE_CI_JOB_NIGHTLY: "true" -t:windows-clang15.0-gnu-nmake: +t:windows-clang16.0-gnu-nmake: extends: - .windows_clang_nmake - .cmake_test_windows_external @@ -1161,7 +1161,7 @@ t:windows-clang15.0-gnu-nmake: needs: - t:windows-vs2022-x64-ninja variables: - CMAKE_CI_BUILD_NAME: windows_clang15.0_gnu_nmake + CMAKE_CI_BUILD_NAME: windows_clang16.0_gnu_nmake CMAKE_CI_JOB_NIGHTLY: "true" t:mingw_osdn_io-mingw_makefiles: diff --git a/.gitlab/ci/clang.ps1 b/.gitlab/ci/clang.ps1 index 29db93d..1fc8d8e 100755 --- a/.gitlab/ci/clang.ps1 +++ b/.gitlab/ci/clang.ps1 @@ -1,10 +1,10 @@ $erroractionpreference = "stop" -if ("$env:CMAKE_CI_BUILD_NAME".Contains("clang15.0")) { - # LLVM/Clang 15.0 - # https://github.com/llvm/llvm-project/releases/tag/llvmorg-15.0.4 - $filename = "llvm-15.0.4-win-x86_64-1" - $sha256sum = "9AA305084C20C27972E103E7B18AAC3F755E0534542AF62FC2F2BF5DDD3C4E1F" +if ("$env:CMAKE_CI_BUILD_NAME".Contains("clang16.0")) { + # LLVM/Clang 16.0 + # https://github.com/llvm/llvm-project/releases/tag/llvmorg-16.0.0 + $filename = "llvm-16.0.0-win-x86_64-1" + $sha256sum = "13F48356BA5892A82E8BB25EB283FDDAA8F23A0F209B6BF6525D2C5E1285B950" } else { throw ('unknown CMAKE_CI_BUILD_NAME: ' + "$env:CMAKE_CI_BUILD_NAME") } diff --git a/.gitlab/ci/configure_debian10_aarch64_ninja.cmake b/.gitlab/ci/configure_debian10_aarch64_ninja.cmake index 7407959..dff0db1 100644 --- a/.gitlab/ci/configure_debian10_aarch64_ninja.cmake +++ b/.gitlab/ci/configure_debian10_aarch64_ninja.cmake @@ -25,6 +25,22 @@ set(CMake_TEST_FindGnuTLS "ON" CACHE BOOL "") set(CMake_TEST_FindGSL "ON" CACHE BOOL "") set(CMake_TEST_FindGTest "ON" CACHE BOOL "") set(CMake_TEST_FindGTK2 "ON" CACHE BOOL "") +set(CMake_TEST_FindHDF5 "ON" CACHE BOOL "") +set(CMake_TEST_FindHDF5_MPICH_C_COMPILER "/usr/bin/h5pcc.mpich" CACHE FILEPATH "") +set(CMake_TEST_FindHDF5_MPICH_C_COMPILER_EXPLICIT "ON" CACHE BOOL "") +# set(CMake_TEST_FindHDF5_MPICH_CXX_COMPILER "/usr/bin/h5c++.mpich" CACHE FILEPATH "") # h5c++.mpich does not exist +# set(CMake_TEST_FindHDF5_MPICH_CXX_COMPILER_EXPLICIT "ON" CACHE BOOL "") +set(CMake_TEST_FindHDF5_MPICH_Fortran_COMPILER "/usr/bin/h5pfc.mpich" CACHE FILEPATH "") +set(CMake_TEST_FindHDF5_MPICH_Fortran_COMPILER_EXPLICIT "ON" CACHE BOOL "") +set(CMake_TEST_FindHDF5_OpenMPI_C_COMPILER "/usr/bin/h5pcc.openmpi" CACHE FILEPATH "") +set(CMake_TEST_FindHDF5_OpenMPI_C_COMPILER_EXPLICIT "ON" CACHE BOOL "") +# set(CMake_TEST_FindHDF5_OpenMPI_CXX_COMPILER "/usr/bin/h5c++.openmpi" CACHE FILEPATH "") # h5c++.openmpi does not exist +# set(CMake_TEST_FindHDF5_OpenMPI_CXX_COMPILER_EXPLICIT "ON" CACHE BOOL "") +set(CMake_TEST_FindHDF5_OpenMPI_Fortran_COMPILER "/usr/bin/h5pfc.openmpi" CACHE FILEPATH "") +set(CMake_TEST_FindHDF5_OpenMPI_Fortran_COMPILER_EXPLICIT "ON" CACHE BOOL "") +set(CMake_TEST_FindHDF5_Serial_C_COMPILER "/usr/bin/h5cc" CACHE FILEPATH "") +set(CMake_TEST_FindHDF5_Serial_CXX_COMPILER "/usr/bin/h5c++" CACHE FILEPATH "") +set(CMake_TEST_FindHDF5_Serial_Fortran_COMPILER "/usr/bin/h5fc" CACHE FILEPATH "") set(CMake_TEST_FindIconv "ON" CACHE BOOL "") set(CMake_TEST_FindICU "ON" CACHE BOOL "") set(CMake_TEST_FindImageMagick "ON" CACHE BOOL "") @@ -65,6 +81,7 @@ set(CMake_TEST_FindRuby "ON" CACHE BOOL "") set(CMake_TEST_FindSDL "ON" CACHE BOOL "") set(CMake_TEST_FindSQLite3 "ON" CACHE BOOL "") set(CMake_TEST_FindTIFF "ON" CACHE BOOL "") +set(CMake_TEST_FindwxWidgets "ON" CACHE BOOL "") set(CMake_TEST_FindX11 "ON" CACHE BOOL "") set(CMake_TEST_FindXalanC "ON" CACHE BOOL "") set(CMake_TEST_FindXercesC "ON" CACHE BOOL "") diff --git a/.gitlab/ci/configure_debian10_ninja.cmake b/.gitlab/ci/configure_debian10_ninja.cmake index e8d6d55..211a2a7 100644 --- a/.gitlab/ci/configure_debian10_ninja.cmake +++ b/.gitlab/ci/configure_debian10_ninja.cmake @@ -29,6 +29,22 @@ set(CMake_TEST_FindGnuTLS "ON" CACHE BOOL "") set(CMake_TEST_FindGSL "ON" CACHE BOOL "") set(CMake_TEST_FindGTest "ON" CACHE BOOL "") set(CMake_TEST_FindGTK2 "ON" CACHE BOOL "") +set(CMake_TEST_FindHDF5 "ON" CACHE BOOL "") +set(CMake_TEST_FindHDF5_MPICH_C_COMPILER "/usr/bin/h5pcc.mpich" CACHE FILEPATH "") +set(CMake_TEST_FindHDF5_MPICH_C_COMPILER_EXPLICIT "ON" CACHE BOOL "") +# set(CMake_TEST_FindHDF5_MPICH_CXX_COMPILER "/usr/bin/h5c++.mpich" CACHE FILEPATH "") # h5c++.mpich does not exist +# set(CMake_TEST_FindHDF5_MPICH_CXX_COMPILER_EXPLICIT "ON" CACHE BOOL "") +set(CMake_TEST_FindHDF5_MPICH_Fortran_COMPILER "/usr/bin/h5pfc.mpich" CACHE FILEPATH "") +set(CMake_TEST_FindHDF5_MPICH_Fortran_COMPILER_EXPLICIT "ON" CACHE BOOL "") +set(CMake_TEST_FindHDF5_OpenMPI_C_COMPILER "/usr/bin/h5pcc.openmpi" CACHE FILEPATH "") +set(CMake_TEST_FindHDF5_OpenMPI_C_COMPILER_EXPLICIT "ON" CACHE BOOL "") +# set(CMake_TEST_FindHDF5_OpenMPI_CXX_COMPILER "/usr/bin/h5c++.openmpi" CACHE FILEPATH "") # h5c++.openmpi does not exist +# set(CMake_TEST_FindHDF5_OpenMPI_CXX_COMPILER_EXPLICIT "ON" CACHE BOOL "") +set(CMake_TEST_FindHDF5_OpenMPI_Fortran_COMPILER "/usr/bin/h5pfc.openmpi" CACHE FILEPATH "") +set(CMake_TEST_FindHDF5_OpenMPI_Fortran_COMPILER_EXPLICIT "ON" CACHE BOOL "") +set(CMake_TEST_FindHDF5_Serial_C_COMPILER "/usr/bin/h5cc" CACHE FILEPATH "") +set(CMake_TEST_FindHDF5_Serial_CXX_COMPILER "/usr/bin/h5c++" CACHE FILEPATH "") +set(CMake_TEST_FindHDF5_Serial_Fortran_COMPILER "/usr/bin/h5fc" CACHE FILEPATH "") set(CMake_TEST_FindIconv "ON" CACHE BOOL "") set(CMake_TEST_FindICU "ON" CACHE BOOL "") set(CMake_TEST_FindImageMagick "ON" CACHE BOOL "") @@ -71,6 +87,7 @@ set(CMake_TEST_FindRuby_RVM "ON" CACHE BOOL "") set(CMake_TEST_FindSDL "ON" CACHE BOOL "") set(CMake_TEST_FindSQLite3 "ON" CACHE BOOL "") set(CMake_TEST_FindTIFF "ON" CACHE BOOL "") +set(CMake_TEST_FindwxWidgets "ON" CACHE BOOL "") set(CMake_TEST_FindX11 "ON" CACHE BOOL "") set(CMake_TEST_FindXalanC "ON" CACHE BOOL "") set(CMake_TEST_FindXercesC "ON" CACHE BOOL "") diff --git a/.gitlab/ci/configure_fedora37_makefiles.cmake b/.gitlab/ci/configure_fedora37_makefiles.cmake index 725cc46..0a271bf 100644 --- a/.gitlab/ci/configure_fedora37_makefiles.cmake +++ b/.gitlab/ci/configure_fedora37_makefiles.cmake @@ -28,6 +28,18 @@ set(CMake_TEST_FindGnuTLS "ON" CACHE BOOL "") set(CMake_TEST_FindGSL "ON" CACHE BOOL "") set(CMake_TEST_FindGTest "ON" CACHE BOOL "") set(CMake_TEST_FindGTK2 "ON" CACHE BOOL "") +set(CMake_TEST_FindHDF5 "ON" CACHE BOOL "") +set(CMake_TEST_FindHDF5_MPICH_C_COMPILER "/usr/lib64/mpich/bin/h5pcc" CACHE FILEPATH "") +# set(CMake_TEST_FindHDF5_MPICH_CXX_COMPILER "/usr/lib64/mpich/bin/h5pc++" CACHE FILEPATH "") # h5pc++ does not exist +set(CMake_TEST_FindHDF5_MPICH_ENVMOD "PATH=path_list_prepend:/usr/lib64/mpich/bin;LD_LIBRARY_PATH=path_list_prepend:/usr/lib64/mpich/lib" CACHE STRING "") +set(CMake_TEST_FindHDF5_MPICH_Fortran_COMPILER "/usr/lib64/mpich/bin/h5pfc" CACHE FILEPATH "") +set(CMake_TEST_FindHDF5_OpenMPI_C_COMPILER "/usr/lib64/openmpi/bin/h5pcc" CACHE FILEPATH "") +set(CMake_TEST_FindHDF5_OpenMPI_ENVMOD "PATH=path_list_prepend:/usr/lib64/openmpi/bin;LD_LIBRARY_PATH=path_list_prepend:/usr/lib64/openmpi/lib" CACHE STRING "") +# set(CMake_TEST_FindHDF5_OpenMPI_CXX_COMPILER "/usr/lib64/openmpi/bin/h5pc++" CACHE FILEPATH "") # h5pc++ does not exist +# set(CMake_TEST_FindHDF5_OpenMPI_Fortran_COMPILER "/usr/lib64/openmpi/bin/h5pfc" CACHE FILEPATH "") # cannot find its own hdf5.mod +set(CMake_TEST_FindHDF5_Serial_C_COMPILER "/usr/bin/h5cc" CACHE FILEPATH "") +set(CMake_TEST_FindHDF5_Serial_CXX_COMPILER "/usr/bin/h5c++" CACHE FILEPATH "") +set(CMake_TEST_FindHDF5_Serial_Fortran_COMPILER "/usr/bin/h5fc" CACHE FILEPATH "") set(CMake_TEST_FindIconv "ON" CACHE BOOL "") set(CMake_TEST_FindICU "ON" CACHE BOOL "") set(CMake_TEST_FindImageMagick "ON" CACHE BOOL "") @@ -45,6 +57,7 @@ set(CMake_TEST_FindLibXslt "ON" CACHE BOOL "") set(CMake_TEST_FindMPI_C "ON" CACHE BOOL "") set(CMake_TEST_FindMPI_CXX "ON" CACHE BOOL "") set(CMake_TEST_FindMPI_Fortran "ON" CACHE BOOL "") +set(CMake_TEST_FindMPI_ENVMOD "PATH=path_list_prepend:/usr/lib64/mpich/bin;LD_LIBRARY_PATH=path_list_prepend:/usr/lib64/mpich/lib" CACHE STRING "") set(CMake_TEST_FindMPI "ON" CACHE BOOL "") set(CMake_TEST_FindODBC "ON" CACHE BOOL "") set(CMake_TEST_FindOpenACC "ON" CACHE BOOL "") @@ -69,6 +82,7 @@ set(CMake_TEST_FindRuby_RVM "ON" CACHE BOOL "") set(CMake_TEST_FindSDL "ON" CACHE BOOL "") set(CMake_TEST_FindSQLite3 "ON" CACHE BOOL "") set(CMake_TEST_FindTIFF "ON" CACHE BOOL "") +set(CMake_TEST_FindwxWidgets "ON" CACHE BOOL "") set(CMake_TEST_FindX11 "ON" CACHE BOOL "") set(CMake_TEST_FindXalanC "ON" CACHE BOOL "") set(CMake_TEST_FindXercesC "ON" CACHE BOOL "") diff --git a/.gitlab/ci/configure_macos_arm64_ninja.cmake b/.gitlab/ci/configure_macos_arm64_ninja.cmake index f59b43c..f2068a1 100644 --- a/.gitlab/ci/configure_macos_arm64_ninja.cmake +++ b/.gitlab/ci/configure_macos_arm64_ninja.cmake @@ -1,3 +1,4 @@ +set(CMake_TEST_FindOpenAL "ON" CACHE BOOL "") set(CMake_TEST_FindOpenMP "ON" CACHE BOOL "") set(CMake_TEST_FindOpenMP_C "ON" CACHE BOOL "") set(CMake_TEST_FindOpenMP_CXX "ON" CACHE BOOL "") diff --git a/.gitlab/ci/configure_macos_x86_64_makefiles.cmake b/.gitlab/ci/configure_macos_x86_64_makefiles.cmake index 3c5d8fe..5d1620d 100644 --- a/.gitlab/ci/configure_macos_x86_64_makefiles.cmake +++ b/.gitlab/ci/configure_macos_x86_64_makefiles.cmake @@ -1,3 +1,4 @@ +set(CMake_TEST_FindOpenAL "ON" CACHE BOOL "") set(CMake_TEST_FindOpenMP "ON" CACHE BOOL "") set(CMake_TEST_FindOpenMP_C "ON" CACHE BOOL "") set(CMake_TEST_FindOpenMP_CXX "ON" CACHE BOOL "") diff --git a/.gitlab/ci/configure_macos_x86_64_ninja.cmake b/.gitlab/ci/configure_macos_x86_64_ninja.cmake index 3c5d8fe..5d1620d 100644 --- a/.gitlab/ci/configure_macos_x86_64_ninja.cmake +++ b/.gitlab/ci/configure_macos_x86_64_ninja.cmake @@ -1,3 +1,4 @@ +set(CMake_TEST_FindOpenAL "ON" CACHE BOOL "") set(CMake_TEST_FindOpenMP "ON" CACHE BOOL "") set(CMake_TEST_FindOpenMP_C "ON" CACHE BOOL "") set(CMake_TEST_FindOpenMP_CXX "ON" CACHE BOOL "") diff --git a/.gitlab/ci/configure_windows_clang_ninja.cmake b/.gitlab/ci/configure_windows_clang_ninja.cmake index ba19834..a66e302 100644 --- a/.gitlab/ci/configure_windows_clang_ninja.cmake +++ b/.gitlab/ci/configure_windows_clang_ninja.cmake @@ -1 +1,5 @@ +if("$ENV{CMAKE_CI_BUILD_NAME}" MATCHES "(^|_)gnu(_|$)") + set(CMake_TEST_MODULE_COMPILATION "named,partitions,internal_partitions,export_bmi,install_bmi,shared" CACHE STRING "") + set(CMake_TEST_MODULE_COMPILATION_RULES "${CMAKE_CURRENT_LIST_DIR}/cxx_modules_rules_clang.cmake" CACHE STRING "") +endif() include("${CMAKE_CURRENT_LIST_DIR}/configure_windows_clang_common.cmake") diff --git a/.gitlab/ci/docker/debian10-aarch64/deps_packages.lst b/.gitlab/ci/docker/debian10-aarch64/deps_packages.lst index 5e30e16..ca83323 100644 --- a/.gitlab/ci/docker/debian10-aarch64/deps_packages.lst +++ b/.gitlab/ci/docker/debian10-aarch64/deps_packages.lst @@ -59,6 +59,9 @@ libgrpc++-dev libgrpc-dev libgsl-dev libgtest-dev libgtk2.0-dev +libhdf5-dev +libhdf5-mpich-dev +libhdf5-openmpi-dev libicu-dev libinput-dev libjpeg-dev @@ -76,6 +79,7 @@ libsdl-dev libsqlite3-dev libtiff-dev libuv1-dev +libwxgtk3.0-dev libx11-dev libxalan-c-dev libxerces-c-dev diff --git a/.gitlab/ci/docker/debian10/deps_packages.lst b/.gitlab/ci/docker/debian10/deps_packages.lst index 3df41f5..0b79675 100644 --- a/.gitlab/ci/docker/debian10/deps_packages.lst +++ b/.gitlab/ci/docker/debian10/deps_packages.lst @@ -62,6 +62,9 @@ libgrpc++-dev libgrpc-dev libgsl-dev libgtest-dev libgtk2.0-dev +libhdf5-dev +libhdf5-mpich-dev +libhdf5-openmpi-dev libicu-dev libinput-dev libjpeg-dev @@ -79,6 +82,7 @@ libsdl-dev libsqlite3-dev libtiff-dev libuv1-dev +libwxgtk3.0-dev libx11-dev libxalan-c-dev libxerces-c-dev diff --git a/.gitlab/ci/docker/fedora37/deps_packages.lst b/.gitlab/ci/docker/fedora37/deps_packages.lst index 9ce8007..51f84ff 100644 --- a/.gitlab/ci/docker/fedora37/deps_packages.lst +++ b/.gitlab/ci/docker/fedora37/deps_packages.lst @@ -73,6 +73,9 @@ grpc-devel grpc-plugins gsl-devel gtest-devel gtk2-devel +hdf5-devel +hdf5-mpich-devel +hdf5-openmpi-devel ImageMagick-c++-devel java-11-openjdk-devel jsoncpp-devel @@ -105,6 +108,7 @@ SDL-devel sqlite-devel swig unixODBC-devel +wxGTK-devel xalan-c-devel xerces-c-devel xz-devel diff --git a/.gitlab/ci/env_fedora37_makefiles.cmake b/.gitlab/ci/env_fedora37_makefiles.cmake index 2bcb6d0..ef13cda 100644 --- a/.gitlab/ci/env_fedora37_makefiles.cmake +++ b/.gitlab/ci/env_fedora37_makefiles.cmake @@ -1,2 +1 @@ set(ENV{MY_RUBY_HOME} "/usr/local/rvm/rubies/ruby-3.0.4") -set(ENV{PATH} "/usr/lib64/mpich/bin:$ENV{PATH}") diff --git a/.gitlab/os-linux.yml b/.gitlab/os-linux.yml index 9a53401..3d62b01 100644 --- a/.gitlab/os-linux.yml +++ b/.gitlab/os-linux.yml @@ -45,7 +45,7 @@ ### Debian .debian10: - image: "kitware/cmake:ci-debian10-x86_64-2023-02-07" + image: "kitware/cmake:ci-debian10-x86_64-2023-03-29" variables: GIT_CLONE_PATH: "$CI_BUILDS_DIR/cmake ci" @@ -60,7 +60,7 @@ CMAKE_CI_NO_INSTALL: 1 .debian10_aarch64: - image: "kitware/cmake:ci-debian10-aarch64-2023-02-07" + image: "kitware/cmake:ci-debian10-aarch64-2023-03-29" variables: GIT_CLONE_PATH: "$CI_BUILDS_DIR/cmake ci" @@ -69,7 +69,7 @@ ### Fedora .fedora37: - image: "kitware/cmake:ci-fedora37-x86_64-2023-02-07" + image: "kitware/cmake:ci-fedora37-x86_64-2023-03-29" variables: GIT_CLONE_PATH: "$CI_BUILDS_DIR/cmake ci/long file name for testing purposes" diff --git a/Auxiliary/vim/syntax/cmake.vim b/Auxiliary/vim/syntax/cmake.vim index f303bd4..3a44d7a 100644 --- a/Auxiliary/vim/syntax/cmake.vim +++ b/Auxiliary/vim/syntax/cmake.vim @@ -128,7 +128,10 @@ syn keyword cmakeProperty contained \ CPACK_WIX_ACL \ CROSSCOMPILING_EMULATOR \ CUDA_ARCHITECTURES + \ CUDA_CUBIN_COMPILATION \ CUDA_EXTENSIONS + \ CUDA_FATBIN_COMPILATION + \ CUDA_OPTIX_COMPILATION \ CUDA_PTX_COMPILATION \ CUDA_RESOLVE_DEVICE_SYMBOLS \ CUDA_RUNTIME_LIBRARY @@ -687,11 +690,14 @@ syn keyword cmakeVariable contained \ CMAKE_AUTOMOC_MOC_OPTIONS \ CMAKE_AUTOMOC_PATH_PREFIX \ CMAKE_AUTOMOC_RELAXED_MODE + \ CMAKE_AUTOMOC_EXECUTABLE \ CMAKE_AUTORCC \ CMAKE_AUTORCC_OPTIONS + \ CMAKE_AUTORCC_EXECUTABLE \ CMAKE_AUTOUIC \ CMAKE_AUTOUIC_OPTIONS \ CMAKE_AUTOUIC_SEARCH_PATHS + \ CMAKE_AUTOUIC_EXECUTABLE \ CMAKE_BACKWARDS_COMPATIBILITY \ CMAKE_BINARY_DIR \ CMAKE_BUILD_RPATH diff --git a/CompileFlags.cmake b/CompileFlags.cmake index 6331af1..f94e079 100644 --- a/CompileFlags.cmake +++ b/CompileFlags.cmake @@ -8,7 +8,7 @@ if(WIN32 AND CMAKE_C_COMPILER_ID STREQUAL "Intel") set(_INTEL_WINDOWS 1) endif() -if(WIN32 AND CMAKE_C_COMPILER_ID STREQUAL "Clang" +if(WIN32 AND CMAKE_C_COMPILER_ID MATCHES "^(Clang|IntelLLVM)$" AND "x${CMAKE_CXX_SIMULATE_ID}" STREQUAL "xMSVC") set(_CLANG_MSVC_WINDOWS 1) endif() @@ -22,18 +22,19 @@ if(MSVC OR _INTEL_WINDOWS OR _CLANG_MSVC_WINDOWS) else() endif() -if(MSVC) - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${CMAKE_CXX_LINKER_WRAPPER_FLAG}-stack:10000000") -endif() - # MSVC 14.28 enables C5105, but the Windows SDK 10.0.18362.0 triggers it. if(CMAKE_C_COMPILER_ID STREQUAL "MSVC" AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 19.28) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -wd5105") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -wd5105") endif() -if(_CLANG_MSVC_WINDOWS AND "x${CMAKE_CXX_COMPILER_FRONTEND_VARIANT}" STREQUAL "xGNU") - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Xlinker -stack:20000000") +# Use a stack size large enough for CMake_DEFAULT_RECURSION_LIMIT. +if(MSVC) + string(APPEND CMAKE_EXE_LINKER_FLAGS " ${CMAKE_CXX_LINKER_WRAPPER_FLAG}-stack:10000000") +elseif(MINGW OR MSYS OR CYGWIN) + string(APPEND CMAKE_EXE_LINKER_FLAGS " -Wl,--stack,10000000") +elseif(_CLANG_MSVC_WINDOWS AND "x${CMAKE_CXX_COMPILER_FRONTEND_VARIANT}" STREQUAL "xGNU") + string(APPEND CMAKE_EXE_LINKER_FLAGS " -Xlinker -stack:20000000") endif() #silence duplicate symbol warnings on AIX diff --git a/Help/command/UNSET_NOTE.txt b/Help/command/UNSET_NOTE.txt new file mode 100644 index 0000000..8dc9125 --- /dev/null +++ b/Help/command/UNSET_NOTE.txt @@ -0,0 +1,9 @@ +.. note:: + + When evaluating :ref:`Variable References` of the form ``${VAR}``, CMake + first searches for a normal variable with that name. If no such normal + variable exists, CMake will then search for a cache entry with that name. + Because of this, **unsetting a normal variable can expose a cache variable + that was previously hidden**. To force a variable reference of the form + ``${VAR}`` to return an empty string, use ``set(<variable> "")``, which + clears the normal variable but leaves it defined. diff --git a/Help/command/cmake_language.rst b/Help/command/cmake_language.rst index 8801a9f..707568c 100644 --- a/Help/command/cmake_language.rst +++ b/Help/command/cmake_language.rst @@ -27,163 +27,155 @@ those created via the :command:`macro` or :command:`function` commands. Calling Commands ^^^^^^^^^^^^^^^^ -.. _CALL: - -.. code-block:: cmake - +.. signature:: cmake_language(CALL <command> [<arg>...]) -Calls the named ``<command>`` with the given arguments (if any). -For example, the code: + Calls the named ``<command>`` with the given arguments (if any). + For example, the code: -.. code-block:: cmake + .. code-block:: cmake - set(message_command "message") - cmake_language(CALL ${message_command} STATUS "Hello World!") + set(message_command "message") + cmake_language(CALL ${message_command} STATUS "Hello World!") -is equivalent to + is equivalent to -.. code-block:: cmake + .. code-block:: cmake - message(STATUS "Hello World!") + message(STATUS "Hello World!") -.. note:: - To ensure consistency of the code, the following commands are not allowed: + .. note:: + To ensure consistency of the code, the following commands are not allowed: - * ``if`` / ``elseif`` / ``else`` / ``endif`` - * ``block`` / ``endblock`` - * ``while`` / ``endwhile`` - * ``foreach`` / ``endforeach`` - * ``function`` / ``endfunction`` - * ``macro`` / ``endmacro`` + * ``if`` / ``elseif`` / ``else`` / ``endif`` + * ``block`` / ``endblock`` + * ``while`` / ``endwhile`` + * ``foreach`` / ``endforeach`` + * ``function`` / ``endfunction`` + * ``macro`` / ``endmacro`` Evaluating Code ^^^^^^^^^^^^^^^ -.. _EVAL: - -.. code-block:: cmake - +.. signature:: cmake_language(EVAL CODE <code>...) + :target: EVAL -Evaluates the ``<code>...`` as CMake code. + Evaluates the ``<code>...`` as CMake code. -For example, the code: + For example, the code: -.. code-block:: cmake + .. code-block:: cmake - set(A TRUE) - set(B TRUE) - set(C TRUE) - set(condition "(A AND B) OR C") + set(A TRUE) + set(B TRUE) + set(C TRUE) + set(condition "(A AND B) OR C") - cmake_language(EVAL CODE " - if (${condition}) - message(STATUS TRUE) - else() - message(STATUS FALSE) - endif()" - ) + cmake_language(EVAL CODE " + if (${condition}) + message(STATUS TRUE) + else() + message(STATUS FALSE) + endif()" + ) -is equivalent to + is equivalent to -.. code-block:: cmake + .. code-block:: cmake - set(A TRUE) - set(B TRUE) - set(C TRUE) - set(condition "(A AND B) OR C") - - file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/eval.cmake " - if (${condition}) - message(STATUS TRUE) - else() - message(STATUS FALSE) - endif()" - ) + set(A TRUE) + set(B TRUE) + set(C TRUE) + set(condition "(A AND B) OR C") - include(${CMAKE_CURRENT_BINARY_DIR}/eval.cmake) + file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/eval.cmake " + if (${condition}) + message(STATUS TRUE) + else() + message(STATUS FALSE) + endif()" + ) + + include(${CMAKE_CURRENT_BINARY_DIR}/eval.cmake) Deferring Calls ^^^^^^^^^^^^^^^ .. versionadded:: 3.19 -.. _DEFER: - -.. code-block:: cmake - +.. signature:: cmake_language(DEFER <options>... CALL <command> [<arg>...]) -Schedules a call to the named ``<command>`` with the given arguments (if any) -to occur at a later time. By default, deferred calls are executed as if -written at the end of the current directory's ``CMakeLists.txt`` file, -except that they run even after a :command:`return` call. Variable -references in arguments are evaluated at the time the deferred call is -executed. + Schedules a call to the named ``<command>`` with the given arguments (if any) + to occur at a later time. By default, deferred calls are executed as if + written at the end of the current directory's ``CMakeLists.txt`` file, + except that they run even after a :command:`return` call. Variable + references in arguments are evaluated at the time the deferred call is + executed. -The options are: + The options are: -``DIRECTORY <dir>`` - Schedule the call for the end of the given directory instead of the - current directory. The ``<dir>`` may reference either a source - directory or its corresponding binary directory. Relative paths are - treated as relative to the current source directory. + ``DIRECTORY <dir>`` + Schedule the call for the end of the given directory instead of the + current directory. The ``<dir>`` may reference either a source + directory or its corresponding binary directory. Relative paths are + treated as relative to the current source directory. - The given directory must be known to CMake, being either the top-level - directory or one added by :command:`add_subdirectory`. Furthermore, - the given directory must not yet be finished processing. This means - it can be the current directory or one of its ancestors. + The given directory must be known to CMake, being either the top-level + directory or one added by :command:`add_subdirectory`. Furthermore, + the given directory must not yet be finished processing. This means + it can be the current directory or one of its ancestors. -``ID <id>`` - Specify an identification for the deferred call. - The ``<id>`` may not be empty and may not begin with a capital letter ``A-Z``. - The ``<id>`` may begin with an underscore (``_``) only if it was generated - automatically by an earlier call that used ``ID_VAR`` to get the id. + ``ID <id>`` + Specify an identification for the deferred call. + The ``<id>`` may not be empty and may not begin with a capital letter ``A-Z``. + The ``<id>`` may begin with an underscore (``_``) only if it was generated + automatically by an earlier call that used ``ID_VAR`` to get the id. -``ID_VAR <var>`` - Specify a variable in which to store the identification for the - deferred call. If ``ID <id>`` is not given, a new identification - will be generated and the generated id will start with an underscore (``_``). + ``ID_VAR <var>`` + Specify a variable in which to store the identification for the + deferred call. If ``ID <id>`` is not given, a new identification + will be generated and the generated id will start with an underscore (``_``). -The currently scheduled list of deferred calls may be retrieved: + The currently scheduled list of deferred calls may be retrieved: -.. code-block:: cmake + .. code-block:: cmake - cmake_language(DEFER [DIRECTORY <dir>] GET_CALL_IDS <var>) + cmake_language(DEFER [DIRECTORY <dir>] GET_CALL_IDS <var>) -This will store in ``<var>`` a :ref:`semicolon-separated list <CMake Language -Lists>` of deferred call ids. The ids are for the directory scope in which -the calls have been deferred to (i.e. where they will be executed), which can -be different to the scope in which they were created. The ``DIRECTORY`` -option can be used to specify the scope for which to retrieve the call ids. -If that option is not given, the call ids for the current directory scope will -be returned. + This will store in ``<var>`` a :ref:`semicolon-separated list <CMake Language + Lists>` of deferred call ids. The ids are for the directory scope in which + the calls have been deferred to (i.e. where they will be executed), which can + be different to the scope in which they were created. The ``DIRECTORY`` + option can be used to specify the scope for which to retrieve the call ids. + If that option is not given, the call ids for the current directory scope + will be returned. -Details of a specific call may be retrieved from its id: + Details of a specific call may be retrieved from its id: -.. code-block:: cmake + .. code-block:: cmake - cmake_language(DEFER [DIRECTORY <dir>] GET_CALL <id> <var>) + cmake_language(DEFER [DIRECTORY <dir>] GET_CALL <id> <var>) -This will store in ``<var>`` a :ref:`semicolon-separated list <CMake Language -Lists>` in which the first element is the name of the command to be -called, and the remaining elements are its unevaluated arguments (any -contained ``;`` characters are included literally and cannot be distinguished -from multiple arguments). If multiple calls are scheduled with the same id, -this retrieves the first one. If no call is scheduled with the given id in -the specified ``DIRECTORY`` scope (or the current directory scope if no -``DIRECTORY`` option is given), this stores an empty string in the variable. + This will store in ``<var>`` a :ref:`semicolon-separated list <CMake Language + Lists>` in which the first element is the name of the command to be + called, and the remaining elements are its unevaluated arguments (any + contained ``;`` characters are included literally and cannot be distinguished + from multiple arguments). If multiple calls are scheduled with the same id, + this retrieves the first one. If no call is scheduled with the given id in + the specified ``DIRECTORY`` scope (or the current directory scope if no + ``DIRECTORY`` option is given), this stores an empty string in the variable. -Deferred calls may be canceled by their id: + Deferred calls may be canceled by their id: -.. code-block:: cmake + .. code-block:: cmake - cmake_language(DEFER [DIRECTORY <dir>] CANCEL_CALL <id>...) + cmake_language(DEFER [DIRECTORY <dir>] CANCEL_CALL <id>...) -This cancels all deferred calls matching any of the given ids in the specified -``DIRECTORY`` scope (or the current directory scope if no ``DIRECTORY`` option -is given). Unknown ids are silently ignored. + This cancels all deferred calls matching any of the given ids in the specified + ``DIRECTORY`` scope (or the current directory scope if no ``DIRECTORY`` option + is given). Unknown ids are silently ignored. Deferred Call Examples """""""""""""""""""""" @@ -229,8 +221,6 @@ also prints:: Deferred Message 1 Deferred Message 2 - -.. _SET_DEPENDENCY_PROVIDER: .. _dependency_providers: Dependency Providers @@ -241,51 +231,50 @@ Dependency Providers .. note:: A high-level introduction to this feature can be found in the :ref:`Using Dependencies Guide <dependency_providers_overview>`. -.. code-block:: cmake - +.. signature:: cmake_language(SET_DEPENDENCY_PROVIDER <command> SUPPORTED_METHODS <methods>...) -When a call is made to :command:`find_package` or -:command:`FetchContent_MakeAvailable`, the call may be forwarded to a -dependency provider which then has the opportunity to fulfill the request. -If the request is for one of the ``<methods>`` specified when the provider -was set, CMake calls the provider's ``<command>`` with a set of -method-specific arguments. If the provider does not fulfill the request, -or if the provider doesn't support the request's method, or no provider -is set, the built-in :command:`find_package` or -:command:`FetchContent_MakeAvailable` implementation is used to fulfill -the request in the usual way. - -One or more of the following values can be specified for the ``<methods>`` -when setting the provider: - -``FIND_PACKAGE`` - The provider command accepts :command:`find_package` requests. - -``FETCHCONTENT_MAKEAVAILABLE_SERIAL`` - The provider command accepts :command:`FetchContent_MakeAvailable` - requests. It expects each dependency to be fed to the provider command - one at a time, not the whole list in one go. - -Only one provider can be set at any point in time. If a provider is already -set when ``cmake_language(SET_DEPENDENCY_PROVIDER)`` is called, the new -provider replaces the previously set one. The specified ``<command>`` must -already exist when ``cmake_language(SET_DEPENDENCY_PROVIDER)`` is called. -As a special case, providing an empty string for the ``<command>`` and no -``<methods>`` will discard any previously set provider. - -The dependency provider can only be set while processing one of the files -specified by the :variable:`CMAKE_PROJECT_TOP_LEVEL_INCLUDES` variable. -Thus, dependency providers can only be set as part of the first call to -:command:`project`. Calling ``cmake_language(SET_DEPENDENCY_PROVIDER)`` -outside of that context will result in an error. - -.. note:: - The choice of dependency provider should always be under the user's control. - As a convenience, a project may choose to provide a file that users can - list in their :variable:`CMAKE_PROJECT_TOP_LEVEL_INCLUDES` variable, but - the use of such a file should always be the user's choice. + When a call is made to :command:`find_package` or + :command:`FetchContent_MakeAvailable`, the call may be forwarded to a + dependency provider which then has the opportunity to fulfill the request. + If the request is for one of the ``<methods>`` specified when the provider + was set, CMake calls the provider's ``<command>`` with a set of + method-specific arguments. If the provider does not fulfill the request, + or if the provider doesn't support the request's method, or no provider + is set, the built-in :command:`find_package` or + :command:`FetchContent_MakeAvailable` implementation is used to fulfill + the request in the usual way. + + One or more of the following values can be specified for the ``<methods>`` + when setting the provider: + + ``FIND_PACKAGE`` + The provider command accepts :command:`find_package` requests. + + ``FETCHCONTENT_MAKEAVAILABLE_SERIAL`` + The provider command accepts :command:`FetchContent_MakeAvailable` + requests. It expects each dependency to be fed to the provider command + one at a time, not the whole list in one go. + + Only one provider can be set at any point in time. If a provider is already + set when ``cmake_language(SET_DEPENDENCY_PROVIDER)`` is called, the new + provider replaces the previously set one. The specified ``<command>`` must + already exist when ``cmake_language(SET_DEPENDENCY_PROVIDER)`` is called. + As a special case, providing an empty string for the ``<command>`` and no + ``<methods>`` will discard any previously set provider. + + The dependency provider can only be set while processing one of the files + specified by the :variable:`CMAKE_PROJECT_TOP_LEVEL_INCLUDES` variable. + Thus, dependency providers can only be set as part of the first call to + :command:`project`. Calling ``cmake_language(SET_DEPENDENCY_PROVIDER)`` + outside of that context will result in an error. + + .. note:: + The choice of dependency provider should always be under the user's control. + As a convenience, a project may choose to provide a file that users can + list in their :variable:`CMAKE_PROJECT_TOP_LEVEL_INCLUDES` variable, but + the use of such a file should always be the user's choice. Provider commands """"""""""""""""" @@ -499,23 +488,21 @@ Getting current message log level .. versionadded:: 3.25 -.. _GET_MESSAGE_LOG_LEVEL: .. _query_message_log_level: -.. code-block:: cmake - +.. signature:: cmake_language(GET_MESSAGE_LOG_LEVEL <output_variable>) -Writes the current :command:`message` logging level -into the given ``<output_variable>``. + Writes the current :command:`message` logging level + into the given ``<output_variable>``. -See :command:`message` for the possible logging levels. + See :command:`message` for the possible logging levels. -The current message logging level can be set either using the -:option:`--log-level <cmake --log-level>` -command line option of the :manual:`cmake(1)` program or using -the :variable:`CMAKE_MESSAGE_LOG_LEVEL` variable. + The current message logging level can be set either using the + :option:`--log-level <cmake --log-level>` + command line option of the :manual:`cmake(1)` program or using + the :variable:`CMAKE_MESSAGE_LOG_LEVEL` variable. -If both the command line option and the variable are set, the command line -option takes precedence. If neither are set, the default logging level -is returned. + If both the command line option and the variable are set, the command line + option takes precedence. If neither are set, the default logging level + is returned. diff --git a/Help/command/file.rst b/Help/command/file.rst index 6ab7421..30a7f4d 100644 --- a/Help/command/file.rst +++ b/Help/command/file.rst @@ -26,7 +26,7 @@ Synopsis `Reading`_ file(`READ`_ <filename> <out-var> [...]) file(`STRINGS`_ <filename> <out-var> [...]) - file(`\<HASH\> <HASH_>`_ <filename> <out-var>) + file(`\<HASH\>`_ <filename> <out-var>) file(`TIMESTAMP`_ <filename> <out-var> [...]) file(`GET_RUNTIME_DEPENDENCIES`_ [...]) @@ -68,1209 +68,1184 @@ Synopsis Reading ^^^^^^^ -.. _READ: - -.. code-block:: cmake - +.. signature:: file(READ <filename> <variable> [OFFSET <offset>] [LIMIT <max-in>] [HEX]) -Read content from a file called ``<filename>`` and store it in a -``<variable>``. Optionally start from the given ``<offset>`` and -read at most ``<max-in>`` bytes. The ``HEX`` option causes data to -be converted to a hexadecimal representation (useful for binary data). If the -``HEX`` option is specified, letters in the output (``a`` through ``f``) are in -lowercase. - -.. _STRINGS: - -.. code-block:: cmake + Read content from a file called ``<filename>`` and store it in a + ``<variable>``. Optionally start from the given ``<offset>`` and + read at most ``<max-in>`` bytes. The ``HEX`` option causes data to + be converted to a hexadecimal representation (useful for binary data). + If the ``HEX`` option is specified, letters in the output + (``a`` through ``f``) are in lowercase. +.. signature:: file(STRINGS <filename> <variable> [<options>...]) -Parse a list of ASCII strings from ``<filename>`` and store it in -``<variable>``. Binary data in the file are ignored. Carriage return -(``\r``, CR) characters are ignored. The options are: + Parse a list of ASCII strings from ``<filename>`` and store it in + ``<variable>``. Binary data in the file are ignored. Carriage return + (``\r``, CR) characters are ignored. The options are: -``LENGTH_MAXIMUM <max-len>`` - Consider only strings of at most a given length. + ``LENGTH_MAXIMUM <max-len>`` + Consider only strings of at most a given length. -``LENGTH_MINIMUM <min-len>`` - Consider only strings of at least a given length. + ``LENGTH_MINIMUM <min-len>`` + Consider only strings of at least a given length. -``LIMIT_COUNT <max-num>`` - Limit the number of distinct strings to be extracted. + ``LIMIT_COUNT <max-num>`` + Limit the number of distinct strings to be extracted. -``LIMIT_INPUT <max-in>`` - Limit the number of input bytes to read from the file. + ``LIMIT_INPUT <max-in>`` + Limit the number of input bytes to read from the file. -``LIMIT_OUTPUT <max-out>`` - Limit the number of total bytes to store in the ``<variable>``. + ``LIMIT_OUTPUT <max-out>`` + Limit the number of total bytes to store in the ``<variable>``. -``NEWLINE_CONSUME`` - Treat newline characters (``\n``, LF) as part of string content - instead of terminating at them. + ``NEWLINE_CONSUME`` + Treat newline characters (``\n``, LF) as part of string content + instead of terminating at them. -``NO_HEX_CONVERSION`` - Intel Hex and Motorola S-record files are automatically converted to - binary while reading unless this option is given. + ``NO_HEX_CONVERSION`` + Intel Hex and Motorola S-record files are automatically converted to + binary while reading unless this option is given. -``REGEX <regex>`` - Consider only strings that match the given regular expression, - as described under :ref:`string(REGEX) <Regex Specification>`. + ``REGEX <regex>`` + Consider only strings that match the given regular expression, + as described under :ref:`string(REGEX) <Regex Specification>`. -``ENCODING <encoding-type>`` - .. versionadded:: 3.1 + ``ENCODING <encoding-type>`` + .. versionadded:: 3.1 - Consider strings of a given encoding. Currently supported encodings are: - ``UTF-8``, ``UTF-16LE``, ``UTF-16BE``, ``UTF-32LE``, ``UTF-32BE``. - If the ``ENCODING`` option is not provided and the file has a Byte Order Mark, - the ``ENCODING`` option will be defaulted to respect the Byte Order Mark. + Consider strings of a given encoding. Currently supported encodings are: + ``UTF-8``, ``UTF-16LE``, ``UTF-16BE``, ``UTF-32LE``, ``UTF-32BE``. + If the ``ENCODING`` option is not provided and the file + has a Byte Order Mark, the ``ENCODING`` option will be defaulted + to respect the Byte Order Mark. - .. versionadded:: 3.2 - Added the ``UTF-16LE``, ``UTF-16BE``, ``UTF-32LE``, ``UTF-32BE`` encodings. + .. versionadded:: 3.2 + Added the ``UTF-16LE``, ``UTF-16BE``, ``UTF-32LE``, ``UTF-32BE`` encodings. -For example, the code + For example, the code -.. code-block:: cmake + .. code-block:: cmake - file(STRINGS myfile.txt myfile) + file(STRINGS myfile.txt myfile) -stores a list in the variable ``myfile`` in which each item is a line -from the input file. + stores a list in the variable ``myfile`` in which each item is a line + from the input file. -.. _HASH: +.. signature:: + file(<HASH> <filename> <variable>) + :target: <HASH> -.. code-block:: cmake + Compute a cryptographic hash of the content of ``<filename>`` and + store it in a ``<variable>``. The supported ``<HASH>`` algorithm names + are those listed by the :command:`string(<HASH>)` command. - file(<HASH> <filename> <variable>) +.. signature:: + file(TIMESTAMP <filename> <variable> [<format>] [UTC]) -Compute a cryptographic hash of the content of ``<filename>`` and -store it in a ``<variable>``. The supported ``<HASH>`` algorithm names -are those listed by the :ref:`string(\<HASH\>) <Supported Hash Algorithms>` -command. + Compute a string representation of the modification time of ``<filename>`` + and store it in ``<variable>``. Should the command be unable to obtain a + timestamp variable will be set to the empty string (""). -.. _TIMESTAMP: + See the :command:`string(TIMESTAMP)` command for documentation of + the ``<format>`` and ``UTC`` options. -.. code-block:: cmake +.. signature:: + file(GET_RUNTIME_DEPENDENCIES [...]) - file(TIMESTAMP <filename> <variable> [<format>] [UTC]) + .. versionadded:: 3.16 -Compute a string representation of the modification time of ``<filename>`` -and store it in ``<variable>``. Should the command be unable to obtain a -timestamp variable will be set to the empty string (""). + Recursively get the list of libraries depended on by the given files: -See the :command:`string(TIMESTAMP)` command for documentation of -the ``<format>`` and ``UTC`` options. + .. code-block:: cmake -.. _GET_RUNTIME_DEPENDENCIES: + file(GET_RUNTIME_DEPENDENCIES + [RESOLVED_DEPENDENCIES_VAR <deps_var>] + [UNRESOLVED_DEPENDENCIES_VAR <unresolved_deps_var>] + [CONFLICTING_DEPENDENCIES_PREFIX <conflicting_deps_prefix>] + [EXECUTABLES [<executable_files>...]] + [LIBRARIES [<library_files>...]] + [MODULES [<module_files>...]] + [DIRECTORIES [<directories>...]] + [BUNDLE_EXECUTABLE <bundle_executable_file>] + [PRE_INCLUDE_REGEXES [<regexes>...]] + [PRE_EXCLUDE_REGEXES [<regexes>...]] + [POST_INCLUDE_REGEXES [<regexes>...]] + [POST_EXCLUDE_REGEXES [<regexes>...]] + [POST_INCLUDE_FILES [<files>...]] + [POST_EXCLUDE_FILES [<files>...]] + ) -.. code-block:: cmake + Please note that this sub-command is not intended to be used in project mode. + It is intended for use at install time, either from code generated by the + :command:`install(RUNTIME_DEPENDENCY_SET)` command, or from code provided by + the project via :command:`install(CODE)` or :command:`install(SCRIPT)`. + For example: - file(GET_RUNTIME_DEPENDENCIES - [RESOLVED_DEPENDENCIES_VAR <deps_var>] - [UNRESOLVED_DEPENDENCIES_VAR <unresolved_deps_var>] - [CONFLICTING_DEPENDENCIES_PREFIX <conflicting_deps_prefix>] - [EXECUTABLES [<executable_files>...]] - [LIBRARIES [<library_files>...]] - [MODULES [<module_files>...]] - [DIRECTORIES [<directories>...]] - [BUNDLE_EXECUTABLE <bundle_executable_file>] - [PRE_INCLUDE_REGEXES [<regexes>...]] - [PRE_EXCLUDE_REGEXES [<regexes>...]] - [POST_INCLUDE_REGEXES [<regexes>...]] - [POST_EXCLUDE_REGEXES [<regexes>...]] - [POST_INCLUDE_FILES [<files>...]] - [POST_EXCLUDE_FILES [<files>...]] - ) + .. code-block:: cmake -.. versionadded:: 3.16 + install(CODE [[ + file(GET_RUNTIME_DEPENDENCIES + # ... + ) + ]]) + + The arguments are as follows: + + ``RESOLVED_DEPENDENCIES_VAR <deps_var>`` + Name of the variable in which to store the list of resolved dependencies. + + ``UNRESOLVED_DEPENDENCIES_VAR <unresolved_deps_var>`` + Name of the variable in which to store the list of unresolved + dependencies. If this variable is not specified, and there are any + unresolved dependencies, an error is issued. + + ``CONFLICTING_DEPENDENCIES_PREFIX <conflicting_deps_prefix>`` + Variable prefix in which to store conflicting dependency information. + Dependencies are conflicting if two files with the same name are found in + two different directories. The list of filenames that conflict are stored + in ``<conflicting_deps_prefix>_FILENAMES``. For each filename, the list + of paths that were found for that filename are stored in + ``<conflicting_deps_prefix>_<filename>``. + + ``EXECUTABLES <executable_files>`` + List of executable files to read for dependencies. These are executables + that are typically created with :command:`add_executable`, but they do + not have to be created by CMake. On Apple platforms, the paths to these + files determine the value of ``@executable_path`` when recursively + resolving the libraries. Specifying any kind of library (``STATIC``, + ``MODULE``, or ``SHARED``) here will result in undefined behavior. + + ``LIBRARIES <library_files>`` + List of library files to read for dependencies. These are libraries that + are typically created with :command:`add_library(SHARED)`, but they do + not have to be created by CMake. Specifying ``STATIC`` libraries, + ``MODULE`` libraries, or executables here will result in undefined + behavior. + + ``MODULES <module_files>`` + List of loadable module files to read for dependencies. These are modules + that are typically created with :command:`add_library(MODULE)`, but they + do not have to be created by CMake. They are typically used by calling + ``dlopen()`` at runtime rather than linked at link time with ``ld -l``. + Specifying ``STATIC`` libraries, ``SHARED`` libraries, or executables + here will result in undefined behavior. + + ``DIRECTORIES <directories>`` + List of additional directories to search for dependencies. On Linux + platforms, these directories are searched if the dependency is not found + in any of the other usual paths. If it is found in such a directory, a + warning is issued, because it means that the file is incomplete (it does + not list all of the directories that contain its dependencies). + On Windows platforms, these directories are searched if the dependency + is not found in any of the other search paths, but no warning is issued, + because searching other paths is a normal part of Windows dependency + resolution. On Apple platforms, this argument has no effect. + + ``BUNDLE_EXECUTABLE <bundle_executable_file>`` + Executable to treat as the "bundle executable" when resolving libraries. + On Apple platforms, this argument determines the value of + ``@executable_path`` when recursively resolving libraries for + ``LIBRARIES`` and ``MODULES`` files. It has no effect on ``EXECUTABLES`` + files. On other platforms, it has no effect. This is typically (but not + always) one of the executables in the ``EXECUTABLES`` argument which + designates the "main" executable of the package. + + The following arguments specify filters for including or excluding libraries + to be resolved. See below for a full description of how they work. + + ``PRE_INCLUDE_REGEXES <regexes>`` + List of pre-include regexes through which to filter the names of + not-yet-resolved dependencies. + + ``PRE_EXCLUDE_REGEXES <regexes>`` + List of pre-exclude regexes through which to filter the names of + not-yet-resolved dependencies. + + ``POST_INCLUDE_REGEXES <regexes>`` + List of post-include regexes through which to filter the names of + resolved dependencies. + + ``POST_EXCLUDE_REGEXES <regexes>`` + List of post-exclude regexes through which to filter the names of + resolved dependencies. + + ``POST_INCLUDE_FILES <files>`` + .. versionadded:: 3.21 + + List of post-include filenames through which to filter the names of + resolved dependencies. Symlinks are resolved when attempting to match + these filenames. + + ``POST_EXCLUDE_FILES <files>`` + .. versionadded:: 3.21 + + List of post-exclude filenames through which to filter the names of + resolved dependencies. Symlinks are resolved when attempting to match + these filenames. + + These arguments can be used to exclude unwanted system libraries when + resolving the dependencies, or to include libraries from a specific + directory. The filtering works as follows: + + 1. If the not-yet-resolved dependency matches any of the + ``PRE_INCLUDE_REGEXES``, steps 2 and 3 are skipped, and the dependency + resolution proceeds to step 4. + + 2. If the not-yet-resolved dependency matches any of the + ``PRE_EXCLUDE_REGEXES``, dependency resolution stops for that dependency. + + 3. Otherwise, dependency resolution proceeds. + + 4. ``file(GET_RUNTIME_DEPENDENCIES)`` searches for the dependency according + to the linking rules of the platform (see below). + + 5. If the dependency is found, and its full path matches one of the + ``POST_INCLUDE_REGEXES`` or ``POST_INCLUDE_FILES``, the full path is added + to the resolved dependencies, and ``file(GET_RUNTIME_DEPENDENCIES)`` + recursively resolves that library's own dependencies. Otherwise, resolution + proceeds to step 6. + + 6. If the dependency is found, but its full path matches one of the + ``POST_EXCLUDE_REGEXES`` or ``POST_EXCLUDE_FILES``, it is not added to the + resolved dependencies, and dependency resolution stops for that dependency. + + 7. If the dependency is found, and its full path does not match either + ``POST_INCLUDE_REGEXES``, ``POST_INCLUDE_FILES``, ``POST_EXCLUDE_REGEXES``, + or ``POST_EXCLUDE_FILES``, the full path is added to the resolved + dependencies, and ``file(GET_RUNTIME_DEPENDENCIES)`` recursively resolves + that library's own dependencies. + + Different platforms have different rules for how dependencies are resolved. + These specifics are described here. + + On Linux platforms, library resolution works as follows: + + 1. If the depending file does not have any ``RUNPATH`` entries, and the + library exists in one of the depending file's ``RPATH`` entries, or its + parents', in that order, the dependency is resolved to that file. + 2. Otherwise, if the depending file has any ``RUNPATH`` entries, and the + library exists in one of those entries, the dependency is resolved to that + file. + 3. Otherwise, if the library exists in one of the directories listed by + ``ldconfig``, the dependency is resolved to that file. + 4. Otherwise, if the library exists in one of the ``DIRECTORIES`` entries, + the dependency is resolved to that file. In this case, a warning is + issued, because finding a file in one of the ``DIRECTORIES`` means that + the depending file is not complete (it does not list all the directories + from which it pulls dependencies). + + 5. Otherwise, the dependency is unresolved. -Recursively get the list of libraries depended on by the given files. + On Windows platforms, library resolution works as follows: -Please note that this sub-command is not intended to be used in project mode. -It is intended for use at install time, either from code generated by the -:command:`install(RUNTIME_DEPENDENCY_SET)` command, or from code provided by -the project via :command:`install(CODE)` or :command:`install(SCRIPT)`. -For example: + 1. DLL dependency names are converted to lowercase for matching filters. + Windows DLL names are case-insensitive, and some linkers mangle the + case of the DLL dependency names. However, this makes it more difficult + for ``PRE_INCLUDE_REGEXES``, ``PRE_EXCLUDE_REGEXES``, + ``POST_INCLUDE_REGEXES``, and ``POST_EXCLUDE_REGEXES`` to properly + filter DLL names - every regex would have to check for both uppercase + and lowercase letters. For example: -.. code-block:: cmake + .. code-block:: cmake - install(CODE [[ - file(GET_RUNTIME_DEPENDENCIES - # ... - ) - ]]) - -The arguments are as follows: - -``RESOLVED_DEPENDENCIES_VAR <deps_var>`` - Name of the variable in which to store the list of resolved dependencies. - -``UNRESOLVED_DEPENDENCIES_VAR <unresolved_deps_var>`` - Name of the variable in which to store the list of unresolved dependencies. - If this variable is not specified, and there are any unresolved dependencies, - an error is issued. - -``CONFLICTING_DEPENDENCIES_PREFIX <conflicting_deps_prefix>`` - Variable prefix in which to store conflicting dependency information. - Dependencies are conflicting if two files with the same name are found in - two different directories. The list of filenames that conflict are stored in - ``<conflicting_deps_prefix>_FILENAMES``. For each filename, the list of paths - that were found for that filename are stored in - ``<conflicting_deps_prefix>_<filename>``. - -``EXECUTABLES <executable_files>`` - List of executable files to read for dependencies. These are executables that - are typically created with :command:`add_executable`, but they do not have to - be created by CMake. On Apple platforms, the paths to these files determine - the value of ``@executable_path`` when recursively resolving the libraries. - Specifying any kind of library (``STATIC``, ``MODULE``, or ``SHARED``) here - will result in undefined behavior. - -``LIBRARIES <library_files>`` - List of library files to read for dependencies. These are libraries that are - typically created with :command:`add_library(SHARED)`, but they do not have - to be created by CMake. Specifying ``STATIC`` libraries, ``MODULE`` - libraries, or executables here will result in undefined behavior. - -``MODULES <module_files>`` - List of loadable module files to read for dependencies. These are modules - that are typically created with :command:`add_library(MODULE)`, but they do - not have to be created by CMake. They are typically used by calling - ``dlopen()`` at runtime rather than linked at link time with ``ld -l``. - Specifying ``STATIC`` libraries, ``SHARED`` libraries, or executables here - will result in undefined behavior. - -``DIRECTORIES <directories>`` - List of additional directories to search for dependencies. On Linux - platforms, these directories are searched if the dependency is not found in - any of the other usual paths. If it is found in such a directory, a warning - is issued, because it means that the file is incomplete (it does not list all - of the directories that contain its dependencies). On Windows platforms, - these directories are searched if the dependency is not found in any of the - other search paths, but no warning is issued, because searching other paths - is a normal part of Windows dependency resolution. On Apple platforms, this - argument has no effect. - -``BUNDLE_EXECUTABLE <bundle_executable_file>`` - Executable to treat as the "bundle executable" when resolving libraries. On - Apple platforms, this argument determines the value of ``@executable_path`` - when recursively resolving libraries for ``LIBRARIES`` and ``MODULES`` files. - It has no effect on ``EXECUTABLES`` files. On other platforms, it has no - effect. This is typically (but not always) one of the executables in the - ``EXECUTABLES`` argument which designates the "main" executable of the - package. - -The following arguments specify filters for including or excluding libraries to -be resolved. See below for a full description of how they work. - -``PRE_INCLUDE_REGEXES <regexes>`` - List of pre-include regexes through which to filter the names of - not-yet-resolved dependencies. - -``PRE_EXCLUDE_REGEXES <regexes>`` - List of pre-exclude regexes through which to filter the names of - not-yet-resolved dependencies. - -``POST_INCLUDE_REGEXES <regexes>`` - List of post-include regexes through which to filter the names of resolved - dependencies. - -``POST_EXCLUDE_REGEXES <regexes>`` - List of post-exclude regexes through which to filter the names of resolved - dependencies. - -``POST_INCLUDE_FILES <files>`` - .. versionadded:: 3.21 + file(GET_RUNTIME_DEPENDENCIES + # ... + PRE_INCLUDE_REGEXES "^[Mm][Yy][Ll][Ii][Bb][Rr][Aa][Rr][Yy]\\.[Dd][Ll][Ll]$" + ) - List of post-include filenames through which to filter the names of resolved - dependencies. Symlinks are resolved when attempting to match these filenames. + Converting the DLL name to lowercase allows the regexes to only match + lowercase names, thus simplifying the regex. For example: -``POST_EXCLUDE_FILES <files>`` - .. versionadded:: 3.21 + .. code-block:: cmake - List of post-exclude filenames through which to filter the names of resolved - dependencies. Symlinks are resolved when attempting to match these filenames. - -These arguments can be used to exclude unwanted system libraries when -resolving the dependencies, or to include libraries from a specific -directory. The filtering works as follows: - -1. If the not-yet-resolved dependency matches any of the - ``PRE_INCLUDE_REGEXES``, steps 2 and 3 are skipped, and the dependency - resolution proceeds to step 4. -2. If the not-yet-resolved dependency matches any of the - ``PRE_EXCLUDE_REGEXES``, dependency resolution stops for that dependency. -3. Otherwise, dependency resolution proceeds. -4. ``file(GET_RUNTIME_DEPENDENCIES)`` searches for the dependency according to - the linking rules of the platform (see below). -5. If the dependency is found, and its full path matches one of the - ``POST_INCLUDE_REGEXES`` or ``POST_INCLUDE_FILES``, the full path is added - to the resolved dependencies, and ``file(GET_RUNTIME_DEPENDENCIES)`` - recursively resolves that library's own dependencies. Otherwise, resolution - proceeds to step 6. -6. If the dependency is found, but its full path matches one of the - ``POST_EXCLUDE_REGEXES`` or ``POST_EXCLUDE_FILES``, it is not added to the - resolved dependencies, and dependency resolution stops for that dependency. -7. If the dependency is found, and its full path does not match either - ``POST_INCLUDE_REGEXES``, ``POST_INCLUDE_FILES``, ``POST_EXCLUDE_REGEXES``, - or ``POST_EXCLUDE_FILES``, the full path is added to the resolved - dependencies, and ``file(GET_RUNTIME_DEPENDENCIES)`` recursively resolves - that library's own dependencies. - -Different platforms have different rules for how dependencies are resolved. -These specifics are described here. - -On Linux platforms, library resolution works as follows: - -1. If the depending file does not have any ``RUNPATH`` entries, and the library - exists in one of the depending file's ``RPATH`` entries, or its parents', in - that order, the dependency is resolved to that file. -2. Otherwise, if the depending file has any ``RUNPATH`` entries, and the - library exists in one of those entries, the dependency is resolved to that - file. -3. Otherwise, if the library exists in one of the directories listed by - ``ldconfig``, the dependency is resolved to that file. -4. Otherwise, if the library exists in one of the ``DIRECTORIES`` entries, the - dependency is resolved to that file. In this case, a warning is issued, - because finding a file in one of the ``DIRECTORIES`` means that the - depending file is not complete (it does not list all the directories from - which it pulls dependencies). -5. Otherwise, the dependency is unresolved. - -On Windows platforms, library resolution works as follows: - -1. The dependent DLL name is converted to lowercase. Windows DLL names are - case-insensitive, and some linkers mangle the case of the DLL dependency - names. However, this makes it more difficult for ``PRE_INCLUDE_REGEXES``, - ``PRE_EXCLUDE_REGEXES``, ``POST_INCLUDE_REGEXES``, and - ``POST_EXCLUDE_REGEXES`` to properly filter DLL names - every regex would - have to check for both uppercase and lowercase letters. For example: - - .. code-block:: cmake - - file(GET_RUNTIME_DEPENDENCIES - # ... - PRE_INCLUDE_REGEXES "^[Mm][Yy][Ll][Ii][Bb][Rr][Aa][Rr][Yy]\\.[Dd][Ll][Ll]$" - ) - - Converting the DLL name to lowercase allows the regexes to only match - lowercase names, thus simplifying the regex. For example: - - .. code-block:: cmake - - file(GET_RUNTIME_DEPENDENCIES - # ... - PRE_INCLUDE_REGEXES "^mylibrary\\.dll$" - ) - - This regex will match ``mylibrary.dll`` regardless of how it is cased, - either on disk or in the depending file. (For example, it will match - ``mylibrary.dll``, ``MyLibrary.dll``, and ``MYLIBRARY.DLL``.) - - Please note that the directory portion of any resolved DLLs retains its - casing and is not converted to lowercase. Only the filename portion is - converted. - -2. (**Not yet implemented**) If the depending file is a Windows Store app, and - the dependency is listed as a dependency in the application's package - manifest, the dependency is resolved to that file. -3. Otherwise, if the library exists in the same directory as the depending - file, the dependency is resolved to that file. -4. Otherwise, if the library exists in either the operating system's - ``system32`` directory or the ``Windows`` directory, in that order, the - dependency is resolved to that file. -5. Otherwise, if the library exists in one of the directories specified by - ``DIRECTORIES``, in the order they are listed, the dependency is resolved to - that file. In this case, a warning is not issued, because searching other - directories is a normal part of Windows library resolution. -6. Otherwise, the dependency is unresolved. - -On Apple platforms, library resolution works as follows: - -1. If the dependency starts with ``@executable_path/``, and an ``EXECUTABLES`` - argument is in the process of being resolved, and replacing - ``@executable_path/`` with the directory of the executable yields an - existing file, the dependency is resolved to that file. -2. Otherwise, if the dependency starts with ``@executable_path/``, and there is - a ``BUNDLE_EXECUTABLE`` argument, and replacing ``@executable_path/`` with - the directory of the bundle executable yields an existing file, the - dependency is resolved to that file. -3. Otherwise, if the dependency starts with ``@loader_path/``, and replacing - ``@loader_path/`` with the directory of the depending file yields an - existing file, the dependency is resolved to that file. -4. Otherwise, if the dependency starts with ``@rpath/``, and replacing - ``@rpath/`` with one of the ``RPATH`` entries of the depending file yields - an existing file, the dependency is resolved to that file. Note that - ``RPATH`` entries that start with ``@executable_path/`` or ``@loader_path/`` - also have these items replaced with the appropriate path. -5. Otherwise, if the dependency is an absolute file that exists, the dependency - is resolved to that file. -6. Otherwise, the dependency is unresolved. - -This function accepts several variables that determine which tool is used for -dependency resolution: - -.. variable:: CMAKE_GET_RUNTIME_DEPENDENCIES_PLATFORM - - Determines which operating system and executable format the files are built - for. This could be one of several values: - - * ``linux+elf`` - * ``windows+pe`` - * ``macos+macho`` - - If this variable is not specified, it is determined automatically by system - introspection. - -.. variable:: CMAKE_GET_RUNTIME_DEPENDENCIES_TOOL - - Determines the tool to use for dependency resolution. It could be one of - several values, depending on the value of - :variable:`CMAKE_GET_RUNTIME_DEPENDENCIES_PLATFORM`: - - ================================================= ============================================= - ``CMAKE_GET_RUNTIME_DEPENDENCIES_PLATFORM`` ``CMAKE_GET_RUNTIME_DEPENDENCIES_TOOL`` - ================================================= ============================================= - ``linux+elf`` ``objdump`` - ``windows+pe`` ``dumpbin`` - ``windows+pe`` ``objdump`` - ``macos+macho`` ``otool`` - ================================================= ============================================= - - If this variable is not specified, it is determined automatically by system - introspection. - -.. variable:: CMAKE_GET_RUNTIME_DEPENDENCIES_COMMAND - - Determines the path to the tool to use for dependency resolution. This is the - actual path to ``objdump``, ``dumpbin``, or ``otool``. - - If this variable is not specified, it is determined by the value of - ``CMAKE_OBJDUMP`` if set, else by system introspection. + file(GET_RUNTIME_DEPENDENCIES + # ... + PRE_INCLUDE_REGEXES "^mylibrary\\.dll$" + ) - .. versionadded:: 3.18 - Use ``CMAKE_OBJDUMP`` if set. + This regex will match ``mylibrary.dll`` regardless of how it is cased, + either on disk or in the depending file. (For example, it will match + ``mylibrary.dll``, ``MyLibrary.dll``, and ``MYLIBRARY.DLL``.) -Writing -^^^^^^^ + .. versionchanged:: 3.27 -.. _WRITE: -.. _APPEND: + The conversion to lowercase only applies while matching filters. + Results reported after filtering case-preserve each DLL name as it is + found on disk, if resolved, and otherwise as it is referenced by the + dependent binary. -.. code-block:: cmake + Prior to CMake 3.27, the results were reported with lowercase DLL + file names, but the directory portion retained its casing. - file(WRITE <filename> <content>...) - file(APPEND <filename> <content>...) + 2. (**Not yet implemented**) If the depending file is a Windows Store app, + and the dependency is listed as a dependency in the application's package + manifest, the dependency is resolved to that file. -Write ``<content>`` into a file called ``<filename>``. If the file does -not exist, it will be created. If the file already exists, ``WRITE`` -mode will overwrite it and ``APPEND`` mode will append to the end. -Any directories in the path specified by ``<filename>`` that do not -exist will be created. + 3. Otherwise, if the library exists in the same directory as the depending + file, the dependency is resolved to that file. -If the file is a build input, use the :command:`configure_file` command -to update the file only when its content changes. + 4. Otherwise, if the library exists in either the operating system's + ``system32`` directory or the ``Windows`` directory, in that order, the + dependency is resolved to that file. -.. _TOUCH: -.. _TOUCH_NOCREATE: + 5. Otherwise, if the library exists in one of the directories specified by + ``DIRECTORIES``, in the order they are listed, the dependency is resolved + to that file. In this case, a warning is not issued, because searching + other directories is a normal part of Windows library resolution. -.. code-block:: cmake + 6. Otherwise, the dependency is unresolved. - file(TOUCH [<files>...]) - file(TOUCH_NOCREATE [<files>...]) + On Apple platforms, library resolution works as follows: -.. versionadded:: 3.12 + 1. If the dependency starts with ``@executable_path/``, and an + ``EXECUTABLES`` argument is in the process of being resolved, and + replacing ``@executable_path/`` with the directory of the executable + yields an existing file, the dependency is resolved to that file. -Create a file with no content if it does not yet exist. If the file already -exists, its access and/or modification will be updated to the time when the -function call is executed. + 2. Otherwise, if the dependency starts with ``@executable_path/``, and there + is a ``BUNDLE_EXECUTABLE`` argument, and replacing ``@executable_path/`` + with the directory of the bundle executable yields an existing file, the + dependency is resolved to that file. -Use TOUCH_NOCREATE to touch a file if it exists but not create it. If a file -does not exist it will be silently ignored. + 3. Otherwise, if the dependency starts with ``@loader_path/``, and replacing + ``@loader_path/`` with the directory of the depending file yields an + existing file, the dependency is resolved to that file. -With TOUCH and TOUCH_NOCREATE the contents of an existing file will not be -modified. + 4. Otherwise, if the dependency starts with ``@rpath/``, and replacing + ``@rpath/`` with one of the ``RPATH`` entries of the depending file + yields an existing file, the dependency is resolved to that file. + Note that ``RPATH`` entries that start with ``@executable_path/`` or + ``@loader_path/`` also have these items replaced with the appropriate + path. -.. _GENERATE: + 5. Otherwise, if the dependency is an absolute file that exists, + the dependency is resolved to that file. -.. code-block:: cmake + 6. Otherwise, the dependency is unresolved. - file(GENERATE OUTPUT output-file - <INPUT input-file|CONTENT content> - [CONDITION expression] [TARGET target] - [NO_SOURCE_PERMISSIONS | USE_SOURCE_PERMISSIONS | - FILE_PERMISSIONS <permissions>...] - [NEWLINE_STYLE [UNIX|DOS|WIN32|LF|CRLF] ]) + This function accepts several variables that determine which tool is used for + dependency resolution: -Generate an output file for each build configuration supported by the current -:manual:`CMake Generator <cmake-generators(7)>`. Evaluate -:manual:`generator expressions <cmake-generator-expressions(7)>` -from the input content to produce the output content. The options are: + .. variable:: CMAKE_GET_RUNTIME_DEPENDENCIES_PLATFORM -``CONDITION <condition>`` - Generate the output file for a particular configuration only if - the condition is true. The condition must be either ``0`` or ``1`` - after evaluating generator expressions. + Determines which operating system and executable format the files are built + for. This could be one of several values: -``CONTENT <content>`` - Use the content given explicitly as input. + * ``linux+elf`` + * ``windows+pe`` + * ``macos+macho`` -``INPUT <input-file>`` - Use the content from a given file as input. + If this variable is not specified, it is determined automatically by system + introspection. - .. versionchanged:: 3.10 - A relative path is treated with respect to the value of - :variable:`CMAKE_CURRENT_SOURCE_DIR`. See policy :policy:`CMP0070`. + .. variable:: CMAKE_GET_RUNTIME_DEPENDENCIES_TOOL -``OUTPUT <output-file>`` - Specify the output file name to generate. Use generator expressions - such as :genex:`$<CONFIG>` to specify a configuration-specific - output file name. Multiple configurations may generate the same output - file only if the generated content is identical. Otherwise, the - ``<output-file>`` must evaluate to an unique name for each configuration. + Determines the tool to use for dependency resolution. It could be one of + several values, depending on the value of + :variable:`CMAKE_GET_RUNTIME_DEPENDENCIES_PLATFORM`: - .. versionchanged:: 3.10 - A relative path (after evaluating generator expressions) is treated - with respect to the value of :variable:`CMAKE_CURRENT_BINARY_DIR`. - See policy :policy:`CMP0070`. + ================================================= ============================================= + ``CMAKE_GET_RUNTIME_DEPENDENCIES_PLATFORM`` ``CMAKE_GET_RUNTIME_DEPENDENCIES_TOOL`` + ================================================= ============================================= + ``linux+elf`` ``objdump`` + ``windows+pe`` ``objdump`` or ``dumpbin`` + ``macos+macho`` ``otool`` + ================================================= ============================================= -``TARGET <target>`` - .. versionadded:: 3.19 + If this variable is not specified, it is determined automatically by system + introspection. - Specify which target to use when evaluating generator expressions that - require a target for evaluation (e.g. - :genex:`$<COMPILE_FEATURES:...>`, - :genex:`$<TARGET_PROPERTY:prop>`). + .. variable:: CMAKE_GET_RUNTIME_DEPENDENCIES_COMMAND -``NO_SOURCE_PERMISSIONS`` - .. versionadded:: 3.20 + Determines the path to the tool to use for dependency resolution. This is + the actual path to ``objdump``, ``dumpbin``, or ``otool``. - The generated file permissions default to the standard 644 value - (-rw-r--r--). + If this variable is not specified, it is determined by the value of + ``CMAKE_OBJDUMP`` if set, else by system introspection. -``USE_SOURCE_PERMISSIONS`` - .. versionadded:: 3.20 + .. versionadded:: 3.18 + Use ``CMAKE_OBJDUMP`` if set. - Transfer the file permissions of the ``INPUT`` file to the generated file. - This is already the default behavior if none of the three permissions-related - keywords are given (``NO_SOURCE_PERMISSIONS``, ``USE_SOURCE_PERMISSIONS`` - or ``FILE_PERMISSIONS``). The ``USE_SOURCE_PERMISSIONS`` keyword mostly - serves as a way of making the intended behavior clearer at the call site. - It is an error to specify this option without ``INPUT``. +Writing +^^^^^^^ -``FILE_PERMISSIONS <permissions>...`` - .. versionadded:: 3.20 +.. signature:: + file(WRITE <filename> <content>...) + file(APPEND <filename> <content>...) - Use the specified permissions for the generated file. + Write ``<content>`` into a file called ``<filename>``. If the file does + not exist, it will be created. If the file already exists, ``WRITE`` + mode will overwrite it and ``APPEND`` mode will append to the end. + Any directories in the path specified by ``<filename>`` that do not + exist will be created. -``NEWLINE_STYLE <style>`` - .. versionadded:: 3.20 + If the file is a build input, use the :command:`configure_file` command + to update the file only when its content changes. - Specify the newline style for the generated file. Specify - ``UNIX`` or ``LF`` for ``\n`` newlines, or specify - ``DOS``, ``WIN32``, or ``CRLF`` for ``\r\n`` newlines. +.. signature:: + file(TOUCH [<files>...]) + file(TOUCH_NOCREATE [<files>...]) -Exactly one ``CONTENT`` or ``INPUT`` option must be given. A specific -``OUTPUT`` file may be named by at most one invocation of ``file(GENERATE)``. -Generated files are modified and their timestamp updated on subsequent cmake -runs only if their content is changed. + .. versionadded:: 3.12 -Note also that ``file(GENERATE)`` does not create the output file until the -generation phase. The output file will not yet have been written when the -``file(GENERATE)`` command returns, it is written only after processing all -of a project's ``CMakeLists.txt`` files. + Create a file with no content if it does not yet exist. If the file already + exists, its access and/or modification will be updated to the time when the + function call is executed. -.. _CONFIGURE: + Use ``TOUCH_NOCREATE`` to touch a file if it exists but not create it. + If a file does not exist it will be silently ignored. -.. code-block:: cmake + With ``TOUCH`` and ``TOUCH_NOCREATE``, the contents of an existing file + will not be modified. - file(CONFIGURE OUTPUT output-file - CONTENT content - [ESCAPE_QUOTES] [@ONLY] - [NEWLINE_STYLE [UNIX|DOS|WIN32|LF|CRLF] ]) +.. signature:: + file(GENERATE [...]) -.. versionadded:: 3.18 + Generate an output file for each build configuration supported by the current + :manual:`CMake Generator <cmake-generators(7)>`. Evaluate + :manual:`generator expressions <cmake-generator-expressions(7)>` + from the input content to produce the output content. -Generate an output file using the input given by ``CONTENT`` and substitute -variable values referenced as ``@VAR@`` or ``${VAR}`` contained therein. The -substitution rules behave the same as the :command:`configure_file` command. -In order to match :command:`configure_file`'s behavior, generator expressions -are not supported for both ``OUTPUT`` and ``CONTENT``. + .. code-block:: cmake -The arguments are: + file(GENERATE OUTPUT <output-file> + <INPUT <input-file>|CONTENT <content>> + [CONDITION <expression>] [TARGET <target>] + [NO_SOURCE_PERMISSIONS | USE_SOURCE_PERMISSIONS | + FILE_PERMISSIONS <permissions>...] + [NEWLINE_STYLE [UNIX|DOS|WIN32|LF|CRLF] ]) -``OUTPUT <output-file>`` - Specify the output file name to generate. A relative path is treated with - respect to the value of :variable:`CMAKE_CURRENT_BINARY_DIR`. - ``<output-file>`` does not support generator expressions. + The options are: -``CONTENT <content>`` - Use the content given explicitly as input. - ``<content>`` does not support generator expressions. + ``CONDITION <condition>`` + Generate the output file for a particular configuration only if + the condition is true. The condition must be either ``0`` or ``1`` + after evaluating generator expressions. -``ESCAPE_QUOTES`` - Escape any substituted quotes with backslashes (C-style). + ``CONTENT <content>`` + Use the content given explicitly as input. -``@ONLY`` - Restrict variable replacement to references of the form ``@VAR@``. - This is useful for configuring scripts that use ``${VAR}`` syntax. + ``INPUT <input-file>`` + Use the content from a given file as input. -``NEWLINE_STYLE <style>`` - Specify the newline style for the output file. Specify - ``UNIX`` or ``LF`` for ``\n`` newlines, or specify - ``DOS``, ``WIN32``, or ``CRLF`` for ``\r\n`` newlines. + .. versionchanged:: 3.10 + A relative path is treated with respect to the value of + :variable:`CMAKE_CURRENT_SOURCE_DIR`. See policy :policy:`CMP0070`. -Filesystem -^^^^^^^^^^ + ``OUTPUT <output-file>`` + Specify the output file name to generate. Use generator expressions + such as :genex:`$<CONFIG>` to specify a configuration-specific + output file name. Multiple configurations may generate the same output + file only if the generated content is identical. Otherwise, the + ``<output-file>`` must evaluate to an unique name for each configuration. -.. _GLOB: -.. _GLOB_RECURSE: + .. versionchanged:: 3.10 + A relative path (after evaluating generator expressions) is treated + with respect to the value of :variable:`CMAKE_CURRENT_BINARY_DIR`. + See policy :policy:`CMP0070`. -.. code-block:: cmake + ``TARGET <target>`` + .. versionadded:: 3.19 - file(GLOB <variable> - [LIST_DIRECTORIES true|false] [RELATIVE <path>] [CONFIGURE_DEPENDS] - [<globbing-expressions>...]) - file(GLOB_RECURSE <variable> [FOLLOW_SYMLINKS] - [LIST_DIRECTORIES true|false] [RELATIVE <path>] [CONFIGURE_DEPENDS] - [<globbing-expressions>...]) + Specify which target to use when evaluating generator expressions that + require a target for evaluation (e.g. + :genex:`$<COMPILE_FEATURES:...>`, + :genex:`$<TARGET_PROPERTY:prop>`). -Generate a list of files that match the ``<globbing-expressions>`` and -store it into the ``<variable>``. Globbing expressions are similar to -regular expressions, but much simpler. If ``RELATIVE`` flag is -specified, the results will be returned as relative paths to the given -path. + ``NO_SOURCE_PERMISSIONS`` + .. versionadded:: 3.20 -.. versionchanged:: 3.6 - The results will be ordered lexicographically. + The generated file permissions default to the standard 644 value + (-rw-r--r--). -On Windows and macOS, globbing is case-insensitive even if the underlying -filesystem is case-sensitive (both filenames and globbing expressions are -converted to lowercase before matching). On other platforms, globbing is -case-sensitive. + ``USE_SOURCE_PERMISSIONS`` + .. versionadded:: 3.20 -.. versionadded:: 3.3 - By default ``GLOB`` lists directories - directories are omitted in result if - ``LIST_DIRECTORIES`` is set to false. + Transfer the file permissions of the ``INPUT`` file to the generated + file. This is already the default behavior if none of the three + permissions-related keywords are given (``NO_SOURCE_PERMISSIONS``, + ``USE_SOURCE_PERMISSIONS`` or ``FILE_PERMISSIONS``). The + ``USE_SOURCE_PERMISSIONS`` keyword mostly serves as a way of making + the intended behavior clearer at the call site. It is an error to + specify this option without ``INPUT``. -.. versionadded:: 3.12 - If the ``CONFIGURE_DEPENDS`` flag is specified, CMake will add logic - to the main build system check target to rerun the flagged ``GLOB`` commands - at build time. If any of the outputs change, CMake will regenerate the build - system. + ``FILE_PERMISSIONS <permissions>...`` + .. versionadded:: 3.20 -.. note:: - We do not recommend using GLOB to collect a list of source files from - your source tree. If no CMakeLists.txt file changes when a source is - added or removed then the generated build system cannot know when to - ask CMake to regenerate. - The ``CONFIGURE_DEPENDS`` flag may not work reliably on all generators, or if - a new generator is added in the future that cannot support it, projects using - it will be stuck. Even if ``CONFIGURE_DEPENDS`` works reliably, there is - still a cost to perform the check on every rebuild. + Use the specified permissions for the generated file. -Examples of globbing expressions include:: + ``NEWLINE_STYLE <style>`` + .. versionadded:: 3.20 - *.cxx - match all files with extension cxx - *.vt? - match all files with extension vta,...,vtz - f[3-5].txt - match files f3.txt, f4.txt, f5.txt + Specify the newline style for the generated file. Specify + ``UNIX`` or ``LF`` for ``\n`` newlines, or specify + ``DOS``, ``WIN32``, or ``CRLF`` for ``\r\n`` newlines. -The ``GLOB_RECURSE`` mode will traverse all the subdirectories of the -matched directory and match the files. Subdirectories that are symlinks -are only traversed if ``FOLLOW_SYMLINKS`` is given or policy -:policy:`CMP0009` is not set to ``NEW``. + Exactly one ``CONTENT`` or ``INPUT`` option must be given. A specific + ``OUTPUT`` file may be named by at most one invocation of ``file(GENERATE)``. + Generated files are modified and their timestamp updated on subsequent cmake + runs only if their content is changed. -.. versionadded:: 3.3 - By default ``GLOB_RECURSE`` omits directories from result list - setting - ``LIST_DIRECTORIES`` to true adds directories to result list. - If ``FOLLOW_SYMLINKS`` is given or policy :policy:`CMP0009` is not set to - ``NEW`` then ``LIST_DIRECTORIES`` treats symlinks as directories. + Note also that ``file(GENERATE)`` does not create the output file until the + generation phase. The output file will not yet have been written when the + ``file(GENERATE)`` command returns, it is written only after processing all + of a project's ``CMakeLists.txt`` files. -Examples of recursive globbing include:: +.. signature:: + file(CONFIGURE OUTPUT <output-file> + CONTENT <content> + [ESCAPE_QUOTES] [@ONLY] + [NEWLINE_STYLE [UNIX|DOS|WIN32|LF|CRLF] ]) + :target: CONFIGURE - /dir/*.py - match all python files in /dir and subdirectories + .. versionadded:: 3.18 -.. _MAKE_DIRECTORY: + Generate an output file using the input given by ``CONTENT`` and substitute + variable values referenced as ``@VAR@`` or ``${VAR}`` contained therein. The + substitution rules behave the same as the :command:`configure_file` command. + In order to match :command:`configure_file`'s behavior, generator expressions + are not supported for both ``OUTPUT`` and ``CONTENT``. -.. code-block:: cmake + The arguments are: - file(MAKE_DIRECTORY [<directories>...]) + ``OUTPUT <output-file>`` + Specify the output file name to generate. A relative path is treated with + respect to the value of :variable:`CMAKE_CURRENT_BINARY_DIR`. + ``<output-file>`` does not support generator expressions. -Create the given directories and their parents as needed. + ``CONTENT <content>`` + Use the content given explicitly as input. + ``<content>`` does not support generator expressions. -.. _REMOVE: -.. _REMOVE_RECURSE: + ``ESCAPE_QUOTES`` + Escape any substituted quotes with backslashes (C-style). -.. code-block:: cmake + ``@ONLY`` + Restrict variable replacement to references of the form ``@VAR@``. + This is useful for configuring scripts that use ``${VAR}`` syntax. - file(REMOVE [<files>...]) - file(REMOVE_RECURSE [<files>...]) + ``NEWLINE_STYLE <style>`` + Specify the newline style for the output file. Specify + ``UNIX`` or ``LF`` for ``\n`` newlines, or specify + ``DOS``, ``WIN32``, or ``CRLF`` for ``\r\n`` newlines. -Remove the given files. The ``REMOVE_RECURSE`` mode will remove the given -files and directories, also non-empty directories. No error is emitted if a -given file does not exist. Relative input paths are evaluated with respect -to the current source directory. +Filesystem +^^^^^^^^^^ -.. versionchanged:: 3.15 - Empty input paths are ignored with a warning. Previous versions of CMake - interpreted empty strings as a relative path with respect to the current - directory and removed its contents. +.. signature:: + file(GLOB <variable> + [LIST_DIRECTORIES true|false] [RELATIVE <path>] [CONFIGURE_DEPENDS] + [<globbing-expressions>...]) + file(GLOB_RECURSE <variable> [FOLLOW_SYMLINKS] + [LIST_DIRECTORIES true|false] [RELATIVE <path>] [CONFIGURE_DEPENDS] + [<globbing-expressions>...]) -.. _RENAME: + Generate a list of files that match the ``<globbing-expressions>`` and + store it into the ``<variable>``. Globbing expressions are similar to + regular expressions, but much simpler. If ``RELATIVE`` flag is + specified, the results will be returned as relative paths to the given + path. + + .. versionchanged:: 3.6 + The results will be ordered lexicographically. + + On Windows and macOS, globbing is case-insensitive even if the underlying + filesystem is case-sensitive (both filenames and globbing expressions are + converted to lowercase before matching). On other platforms, globbing is + case-sensitive. + + .. versionadded:: 3.3 + By default ``GLOB`` lists directories. Directories are omitted in the + result if ``LIST_DIRECTORIES`` is set to false. + + .. versionadded:: 3.12 + If the ``CONFIGURE_DEPENDS`` flag is specified, CMake will add logic + to the main build system check target to rerun the flagged ``GLOB`` + commands at build time. If any of the outputs change, CMake will regenerate + the build system. + + .. note:: + We do not recommend using GLOB to collect a list of source files from + your source tree. If no CMakeLists.txt file changes when a source is + added or removed then the generated build system cannot know when to + ask CMake to regenerate. + The ``CONFIGURE_DEPENDS`` flag may not work reliably on all generators, or + if a new generator is added in the future that cannot support it, projects + using it will be stuck. Even if ``CONFIGURE_DEPENDS`` works reliably, there + is still a cost to perform the check on every rebuild. + + Examples of globbing expressions include: + + ============== ====================================================== + ``*.cxx`` match all files with extension ``cxx`` + ``*.vt?`` match all files with extension ``vta``, ..., ``vtz`` + ``f[3-5].txt`` match files ``f3.txt``, ``f4.txt``, ``f5.txt`` + ============== ====================================================== + + The ``GLOB_RECURSE`` mode will traverse all the subdirectories of the + matched directory and match the files. Subdirectories that are symlinks + are only traversed if ``FOLLOW_SYMLINKS`` is given or policy + :policy:`CMP0009` is not set to ``NEW``. + + .. versionadded:: 3.3 + By default ``GLOB_RECURSE`` omits directories from result list. Setting + ``LIST_DIRECTORIES`` to true adds directories to result list. + If ``FOLLOW_SYMLINKS`` is given or policy :policy:`CMP0009` is not set to + ``NEW`` then ``LIST_DIRECTORIES`` treats symlinks as directories. + + Examples of recursive globbing include: + + ============== ====================================================== + ``/dir/*.py`` match all python files in ``/dir`` and subdirectories + ============== ====================================================== + +.. signature:: + file(MAKE_DIRECTORY [<directories>...]) -.. code-block:: cmake + Create the given directories and their parents as needed. - file(RENAME <oldname> <newname> - [RESULT <result>] - [NO_REPLACE]) +.. signature:: + file(REMOVE [<files>...]) + file(REMOVE_RECURSE [<files>...]) -Move a file or directory within a filesystem from ``<oldname>`` to -``<newname>``, replacing the destination atomically. + Remove the given files. The ``REMOVE_RECURSE`` mode will remove the given + files and directories, including non-empty directories. No error is emitted + if a given file does not exist. Relative input paths are evaluated with + respect to the current source directory. -The options are: + .. versionchanged:: 3.15 + Empty input paths are ignored with a warning. Previous versions of CMake + interpreted empty strings as a relative path with respect to the current + directory and removed its contents. -``RESULT <result>`` - .. versionadded:: 3.21 +.. signature:: + file(RENAME <oldname> <newname> [RESULT <result>] [NO_REPLACE]) - Set ``<result>`` variable to ``0`` on success or an error message otherwise. - If ``RESULT`` is not specified and the operation fails, an error is emitted. + Move a file or directory within a filesystem from ``<oldname>`` to + ``<newname>``, replacing the destination atomically. -``NO_REPLACE`` - .. versionadded:: 3.21 + The options are: - If the ``<newname>`` path already exists, do not replace it. - If ``RESULT <result>`` is used, the result variable will be - set to ``NO_REPLACE``. Otherwise, an error is emitted. + ``RESULT <result>`` + .. versionadded:: 3.21 -.. _COPY_FILE: + Set ``<result>`` variable to ``0`` on success or an error message + otherwise. If ``RESULT`` is not specified and the operation fails, + an error is emitted. -.. code-block:: cmake + ``NO_REPLACE`` + .. versionadded:: 3.21 + If the ``<newname>`` path already exists, do not replace it. + If ``RESULT <result>`` is used, the result variable will be + set to ``NO_REPLACE``. Otherwise, an error is emitted. + +.. signature:: file(COPY_FILE <oldname> <newname> [RESULT <result>] [ONLY_IF_DIFFERENT] [INPUT_MAY_BE_RECENT]) -.. versionadded:: 3.21 - -Copy a file from ``<oldname>`` to ``<newname>``. Directories are not -supported. Symlinks are ignored and ``<oldfile>``'s content is read and -written to ``<newname>`` as a new file. - -The options are: - -``RESULT <result>`` - Set ``<result>`` variable to ``0`` on success or an error message otherwise. - If ``RESULT`` is not specified and the operation fails, an error is emitted. + .. versionadded:: 3.21 -``ONLY_IF_DIFFERENT`` - If the ``<newname>`` path already exists, do not replace it if the file's - contents are already the same as ``<oldname>`` (this avoids updating - ``<newname>``'s timestamp). + Copy a file from ``<oldname>`` to ``<newname>``. Directories are not + supported. Symlinks are ignored and ``<oldfile>``'s content is read and + written to ``<newname>`` as a new file. -``INPUT_MAY_BE_RECENT`` - .. versionadded:: 3.26 + The options are: - Tell CMake that the input file may have been recently created. This is - meaningful only on Windows, where files may be inaccessible for a short - time after they are created. With this option, if permission is denied, - CMake will retry reading the input a few times. + ``RESULT <result>`` + Set ``<result>`` variable to ``0`` on success or an error message + otherwise. If ``RESULT`` is not specified and the operation fails, + an error is emitted. -This sub-command has some similarities to :command:`configure_file` with the -``COPYONLY`` option. An important difference is that :command:`configure_file` -creates a dependency on the source file, so CMake will be re-run if it changes. -The ``file(COPY_FILE)`` sub-command does not create such a dependency. + ``ONLY_IF_DIFFERENT`` + If the ``<newname>`` path already exists, do not replace it if the file's + contents are already the same as ``<oldname>`` (this avoids updating + ``<newname>``'s timestamp). -See also the ``file(COPY)`` sub-command just below which provides -further file-copying capabilities. + ``INPUT_MAY_BE_RECENT`` + .. versionadded:: 3.26 -.. _COPY: -.. _INSTALL: + Tell CMake that the input file may have been recently created. This is + meaningful only on Windows, where files may be inaccessible for a short + time after they are created. With this option, if permission is denied, + CMake will retry reading the input a few times. -.. code-block:: cmake + This sub-command has some similarities to :command:`configure_file` + with the ``COPYONLY`` option. An important difference is that + :command:`configure_file` creates a dependency on the source file, + so CMake will be re-run if it changes. The ``file(COPY_FILE)`` + sub-command does not create such a dependency. - file(<COPY|INSTALL> <files>... DESTINATION <dir> - [NO_SOURCE_PERMISSIONS | USE_SOURCE_PERMISSIONS] - [FILE_PERMISSIONS <permissions>...] - [DIRECTORY_PERMISSIONS <permissions>...] - [FOLLOW_SYMLINK_CHAIN] - [FILES_MATCHING] - [[PATTERN <pattern> | REGEX <regex>] - [EXCLUDE] [PERMISSIONS <permissions>...]] [...]) + See also the :command:`file(COPY)` sub-command just below which provides + further file-copying capabilities. -.. note:: +.. signature:: + file(COPY [...]) + file(INSTALL [...]) - For a simple file copying operation, the ``file(COPY_FILE)`` sub-command - just above may be easier to use. + The ``COPY`` signature copies files, directories, and symlinks to a + destination folder. Relative input paths are evaluated with respect + to the current source directory, and a relative destination is + evaluated with respect to the current build directory. Copying + preserves input file timestamps, and optimizes out a file if it exists + at the destination with the same timestamp. Copying preserves input + permissions unless explicit permissions or ``NO_SOURCE_PERMISSIONS`` + are given (default is ``USE_SOURCE_PERMISSIONS``). -The ``COPY`` signature copies files, directories, and symlinks to a -destination folder. Relative input paths are evaluated with respect -to the current source directory, and a relative destination is -evaluated with respect to the current build directory. Copying -preserves input file timestamps, and optimizes out a file if it exists -at the destination with the same timestamp. Copying preserves input -permissions unless explicit permissions or ``NO_SOURCE_PERMISSIONS`` -are given (default is ``USE_SOURCE_PERMISSIONS``). + .. code-block:: cmake -.. versionadded:: 3.15 - If ``FOLLOW_SYMLINK_CHAIN`` is specified, ``COPY`` will recursively resolve - the symlinks at the paths given until a real file is found, and install - a corresponding symlink in the destination for each symlink encountered. For - each symlink that is installed, the resolution is stripped of the directory, - leaving only the filename, meaning that the new symlink points to a file in - the same directory as the symlink. This feature is useful on some Unix systems, - where libraries are installed as a chain of symlinks with version numbers, with - less specific versions pointing to more specific versions. - ``FOLLOW_SYMLINK_CHAIN`` will install all of these symlinks and the library - itself into the destination directory. For example, if you have the following - directory structure: + file(<COPY|INSTALL> <files>... DESTINATION <dir> + [NO_SOURCE_PERMISSIONS | USE_SOURCE_PERMISSIONS] + [FILE_PERMISSIONS <permissions>...] + [DIRECTORY_PERMISSIONS <permissions>...] + [FOLLOW_SYMLINK_CHAIN] + [FILES_MATCHING] + [[PATTERN <pattern> | REGEX <regex>] + [EXCLUDE] [PERMISSIONS <permissions>...]] [...]) -* ``/opt/foo/lib/libfoo.so.1.2.3`` -* ``/opt/foo/lib/libfoo.so.1.2 -> libfoo.so.1.2.3`` -* ``/opt/foo/lib/libfoo.so.1 -> libfoo.so.1.2`` -* ``/opt/foo/lib/libfoo.so -> libfoo.so.1`` + .. note:: -and you do: + For a simple file copying operation, the :command:`file(COPY_FILE)` + sub-command just above may be easier to use. -.. code-block:: cmake + .. versionadded:: 3.15 + If ``FOLLOW_SYMLINK_CHAIN`` is specified, ``COPY`` will recursively resolve + the symlinks at the paths given until a real file is found, and install + a corresponding symlink in the destination for each symlink encountered. + For each symlink that is installed, the resolution is stripped of the + directory, leaving only the filename, meaning that the new symlink points + to a file in the same directory as the symlink. This feature is useful on + some Unix systems, where libraries are installed as a chain of symlinks + with version numbers, with less specific versions pointing to more specific + versions. ``FOLLOW_SYMLINK_CHAIN`` will install all of these symlinks and + the library itself into the destination directory. For example, if you have + the following directory structure: - file(COPY /opt/foo/lib/libfoo.so DESTINATION lib FOLLOW_SYMLINK_CHAIN) + * ``/opt/foo/lib/libfoo.so.1.2.3`` + * ``/opt/foo/lib/libfoo.so.1.2 -> libfoo.so.1.2.3`` + * ``/opt/foo/lib/libfoo.so.1 -> libfoo.so.1.2`` + * ``/opt/foo/lib/libfoo.so -> libfoo.so.1`` -This will install all of the symlinks and ``libfoo.so.1.2.3`` itself into -``lib``. + and you do: -See the :command:`install(DIRECTORY)` command for documentation of -permissions, ``FILES_MATCHING``, ``PATTERN``, ``REGEX``, and -``EXCLUDE`` options. Copying directories preserves the structure -of their content even if options are used to select a subset of -files. + .. code-block:: cmake -The ``INSTALL`` signature differs slightly from ``COPY``: it prints -status messages, and ``NO_SOURCE_PERMISSIONS`` is default. + file(COPY /opt/foo/lib/libfoo.so DESTINATION lib FOLLOW_SYMLINK_CHAIN) -Installation scripts generated by the :command:`install` command -use this signature (with some undocumented options for internal use). + This will install all of the symlinks and ``libfoo.so.1.2.3`` itself into + ``lib``. -.. versionchanged:: 3.22 + See the :command:`install(DIRECTORY)` command for documentation of + permissions, ``FILES_MATCHING``, ``PATTERN``, ``REGEX``, and + ``EXCLUDE`` options. Copying directories preserves the structure + of their content even if options are used to select a subset of + files. - The environment variable :envvar:`CMAKE_INSTALL_MODE` can override the - default copying behavior of :command:`file(INSTALL)`. + The ``INSTALL`` signature differs slightly from ``COPY``: it prints + status messages, and ``NO_SOURCE_PERMISSIONS`` is default. Installation + scripts generated by the :command:`install` command use this signature + (with some undocumented options for internal use). -.. _SIZE: + .. versionchanged:: 3.22 -.. code-block:: cmake + The environment variable :envvar:`CMAKE_INSTALL_MODE` can override the + default copying behavior of :command:`file(INSTALL)`. +.. signature:: file(SIZE <filename> <variable>) -.. versionadded:: 3.14 - -Determine the file size of the ``<filename>`` and put the result in -``<variable>`` variable. Requires that ``<filename>`` is a valid path -pointing to a file and is readable. + .. versionadded:: 3.14 -.. _READ_SYMLINK: - -.. code-block:: cmake + Determine the file size of the ``<filename>`` and put the result in + ``<variable>`` variable. Requires that ``<filename>`` is a valid path + pointing to a file and is readable. +.. signature:: file(READ_SYMLINK <linkname> <variable>) -.. versionadded:: 3.14 - -This subcommand queries the symlink ``<linkname>`` and stores the path it -points to in the result ``<variable>``. If ``<linkname>`` does not exist or -is not a symlink, CMake issues a fatal error. + .. versionadded:: 3.14 -Note that this command returns the raw symlink path and does not resolve -a relative path. The following is an example of how to ensure that an -absolute path is obtained: + Query the symlink ``<linkname>`` and stores the path it points to + in the result ``<variable>``. If ``<linkname>`` does not exist + or is not a symlink, CMake issues a fatal error. -.. code-block:: cmake + Note that this command returns the raw symlink path and does not resolve + a relative path. The following is an example of how to ensure that an + absolute path is obtained: - set(linkname "/path/to/foo.sym") - file(READ_SYMLINK "${linkname}" result) - if(NOT IS_ABSOLUTE "${result}") - get_filename_component(dir "${linkname}" DIRECTORY) - set(result "${dir}/${result}") - endif() - -.. _CREATE_LINK: + .. code-block:: cmake -.. code-block:: cmake + set(linkname "/path/to/foo.sym") + file(READ_SYMLINK "${linkname}" result) + if(NOT IS_ABSOLUTE "${result}") + get_filename_component(dir "${linkname}" DIRECTORY) + set(result "${dir}/${result}") + endif() +.. signature:: file(CREATE_LINK <original> <linkname> [RESULT <result>] [COPY_ON_ERROR] [SYMBOLIC]) -.. versionadded:: 3.14 + .. versionadded:: 3.14 -Create a link ``<linkname>`` that points to ``<original>``. -It will be a hard link by default, but providing the ``SYMBOLIC`` option -results in a symbolic link instead. Hard links require that ``original`` -exists and is a file, not a directory. If ``<linkname>`` already exists, -it will be overwritten. + Create a link ``<linkname>`` that points to ``<original>``. + It will be a hard link by default, but providing the ``SYMBOLIC`` option + results in a symbolic link instead. Hard links require that ``original`` + exists and is a file, not a directory. If ``<linkname>`` already exists, + it will be overwritten. -The ``<result>`` variable, if specified, receives the status of the operation. -It is set to ``0`` upon success or an error message otherwise. If ``RESULT`` -is not specified and the operation fails, a fatal error is emitted. + The ``<result>`` variable, if specified, receives the status of the + operation. It is set to ``0`` upon success or an error message otherwise. + If ``RESULT`` is not specified and the operation fails, a fatal error is + emitted. -Specifying ``COPY_ON_ERROR`` enables copying the file as a fallback if -creating the link fails. It can be useful for handling situations such as -``<original>`` and ``<linkname>`` being on different drives or mount points, -which would make them unable to support a hard link. - -.. _CHMOD: - -.. code-block:: cmake + Specifying ``COPY_ON_ERROR`` enables copying the file as a fallback if + creating the link fails. It can be useful for handling situations such as + ``<original>`` and ``<linkname>`` being on different drives or mount points, + which would make them unable to support a hard link. +.. signature:: file(CHMOD <files>... <directories>... - [PERMISSIONS <permissions>...] - [FILE_PERMISSIONS <permissions>...] - [DIRECTORY_PERMISSIONS <permissions>...]) - -.. versionadded:: 3.19 - -Set the permissions for the ``<files>...`` and ``<directories>...`` specified. -Valid permissions are ``OWNER_READ``, ``OWNER_WRITE``, ``OWNER_EXECUTE``, -``GROUP_READ``, ``GROUP_WRITE``, ``GROUP_EXECUTE``, ``WORLD_READ``, -``WORLD_WRITE``, ``WORLD_EXECUTE``, ``SETUID``, ``SETGID``. - -Valid combination of keywords are: + [PERMISSIONS <permissions>...] + [FILE_PERMISSIONS <permissions>...] + [DIRECTORY_PERMISSIONS <permissions>...]) -``PERMISSIONS`` - All items are changed. + .. versionadded:: 3.19 -``FILE_PERMISSIONS`` - Only files are changed. + Set the permissions for the ``<files>...`` and ``<directories>...`` + specified. Valid permissions are ``OWNER_READ``, ``OWNER_WRITE``, + ``OWNER_EXECUTE``, ``GROUP_READ``, ``GROUP_WRITE``, ``GROUP_EXECUTE``, + ``WORLD_READ``, ``WORLD_WRITE``, ``WORLD_EXECUTE``, ``SETUID``, ``SETGID``. -``DIRECTORY_PERMISSIONS`` - Only directories are changed. + Valid combination of keywords are: -``PERMISSIONS`` and ``FILE_PERMISSIONS`` - ``FILE_PERMISSIONS`` overrides ``PERMISSIONS`` for files. + ``PERMISSIONS`` + All items are changed. -``PERMISSIONS`` and ``DIRECTORY_PERMISSIONS`` - ``DIRECTORY_PERMISSIONS`` overrides ``PERMISSIONS`` for directories. + ``FILE_PERMISSIONS`` + Only files are changed. -``FILE_PERMISSIONS`` and ``DIRECTORY_PERMISSIONS`` - Use ``FILE_PERMISSIONS`` for files and ``DIRECTORY_PERMISSIONS`` for - directories. + ``DIRECTORY_PERMISSIONS`` + Only directories are changed. + ``PERMISSIONS`` and ``FILE_PERMISSIONS`` + ``FILE_PERMISSIONS`` overrides ``PERMISSIONS`` for files. -.. _CHMOD_RECURSE: + ``PERMISSIONS`` and ``DIRECTORY_PERMISSIONS`` + ``DIRECTORY_PERMISSIONS`` overrides ``PERMISSIONS`` for directories. -.. code-block:: cmake + ``FILE_PERMISSIONS`` and ``DIRECTORY_PERMISSIONS`` + Use ``FILE_PERMISSIONS`` for files and ``DIRECTORY_PERMISSIONS`` for + directories. +.. signature:: file(CHMOD_RECURSE <files>... <directories>... [PERMISSIONS <permissions>...] [FILE_PERMISSIONS <permissions>...] [DIRECTORY_PERMISSIONS <permissions>...]) -.. versionadded:: 3.19 + .. versionadded:: 3.19 + + Same as :cref:`CHMOD`, but change the permissions of files and directories + present in the ``<directories>...`` recursively. -Same as `CHMOD`_, but change the permissions of files and directories present in -the ``<directories>...`` recursively. Path Conversion ^^^^^^^^^^^^^^^ -.. _REAL_PATH: - -.. code-block:: cmake - +.. signature:: file(REAL_PATH <path> <out-var> [BASE_DIRECTORY <dir>] [EXPAND_TILDE]) -.. versionadded:: 3.19 - -Compute the absolute path to an existing file or directory with symlinks -resolved. - -``BASE_DIRECTORY <dir>`` - If the provided ``<path>`` is a relative path, it is evaluated relative to the - given base directory ``<dir>``. If no base directory is provided, the default - base directory will be :variable:`CMAKE_CURRENT_SOURCE_DIR`. + .. versionadded:: 3.19 -``EXPAND_TILDE`` - .. versionadded:: 3.21 + Compute the absolute path to an existing file or directory with symlinks + resolved. The options are: - If the ``<path>`` is ``~`` or starts with ``~/``, the ``~`` is replaced by - the user's home directory. The path to the home directory is obtained from - environment variables. On Windows, the ``USERPROFILE`` environment variable - is used, falling back to the ``HOME`` environment variable if ``USERPROFILE`` - is not defined. On all other platforms, only ``HOME`` is used. + ``BASE_DIRECTORY <dir>`` + If the provided ``<path>`` is a relative path, it is evaluated relative + to the given base directory ``<dir>``. If no base directory is provided, + the default base directory will be :variable:`CMAKE_CURRENT_SOURCE_DIR`. -.. _RELATIVE_PATH: + ``EXPAND_TILDE`` + .. versionadded:: 3.21 -.. code-block:: cmake + If the ``<path>`` is ``~`` or starts with ``~/``, the ``~`` is replaced + by the user's home directory. The path to the home directory is obtained + from environment variables. On Windows, the ``USERPROFILE`` environment + variable is used, falling back to the ``HOME`` environment variable + if ``USERPROFILE`` is not defined. On all other platforms, only ``HOME`` + is used. +.. signature:: file(RELATIVE_PATH <variable> <directory> <file>) -Compute the relative path from a ``<directory>`` to a ``<file>`` and -store it in the ``<variable>``. - -.. _TO_CMAKE_PATH: -.. _TO_NATIVE_PATH: - -.. code-block:: cmake + Compute the relative path from a ``<directory>`` to a ``<file>`` and + store it in the ``<variable>``. +.. signature:: file(TO_CMAKE_PATH "<path>" <variable>) file(TO_NATIVE_PATH "<path>" <variable>) -The ``TO_CMAKE_PATH`` mode converts a native ``<path>`` into a cmake-style -path with forward-slashes (``/``). The input can be a single path or a -system search path like ``$ENV{PATH}``. A search path will be converted -to a cmake-style list separated by ``;`` characters. + The ``TO_CMAKE_PATH`` mode converts a native ``<path>`` into a cmake-style + path with forward-slashes (``/``). The input can be a single path or a + system search path like ``$ENV{PATH}``. A search path will be converted + to a cmake-style list separated by ``;`` characters. -The ``TO_NATIVE_PATH`` mode converts a cmake-style ``<path>`` into a native -path with platform-specific slashes (``\`` on Windows hosts and ``/`` -elsewhere). + The ``TO_NATIVE_PATH`` mode converts a cmake-style ``<path>`` into a native + path with platform-specific slashes (``\`` on Windows hosts and ``/`` + elsewhere). -Always use double quotes around the ``<path>`` to be sure it is treated -as a single argument to this command. + Always use double quotes around the ``<path>`` to be sure it is treated + as a single argument to this command. Transfer ^^^^^^^^ -.. _DOWNLOAD: -.. _UPLOAD: +.. signature:: + file(DOWNLOAD <url> [<file>] [<options>...]) + file(UPLOAD <file> <url> [<options>...]) -.. code-block:: cmake + The ``DOWNLOAD`` subcommand downloads the given ``<url>`` to a local + ``<file>``. The ``UPLOAD`` mode uploads a local ``<file>`` to a given + ``<url>``. - file(DOWNLOAD <url> [<file>] [<options>...]) - file(UPLOAD <file> <url> [<options>...]) + .. versionadded:: 3.19 + If ``<file>`` is not specified for ``file(DOWNLOAD)``, the file is not + saved. This can be useful if you want to know if a file can be downloaded + (for example, to check that it exists) without actually saving it anywhere. -The ``DOWNLOAD`` subcommand downloads the given ``<url>`` to a local ``<file>``. -The ``UPLOAD`` mode uploads a local ``<file>`` to a given ``<url>``. + Options to both ``DOWNLOAD`` and ``UPLOAD`` are: -.. versionadded:: 3.19 - If ``<file>`` is not specified for ``file(DOWNLOAD)``, the file is not saved. - This can be useful if you want to know if a file can be downloaded (for example, - to check that it exists) without actually saving it anywhere. + ``INACTIVITY_TIMEOUT <seconds>`` + Terminate the operation after a period of inactivity. -Options to both ``DOWNLOAD`` and ``UPLOAD`` are: + ``LOG <variable>`` + Store a human-readable log of the operation in a variable. -``INACTIVITY_TIMEOUT <seconds>`` - Terminate the operation after a period of inactivity. + ``SHOW_PROGRESS`` + Print progress information as status messages until the operation is + complete. -``LOG <variable>`` - Store a human-readable log of the operation in a variable. + ``STATUS <variable>`` + Store the resulting status of the operation in a variable. + The status is a ``;`` separated list of length 2. + The first element is the numeric return value for the operation, + and the second element is a string value for the error. + A ``0`` numeric error means no error in the operation. -``SHOW_PROGRESS`` - Print progress information as status messages until the operation is - complete. + ``TIMEOUT <seconds>`` + Terminate the operation after a given total time has elapsed. -``STATUS <variable>`` - Store the resulting status of the operation in a variable. - The status is a ``;`` separated list of length 2. - The first element is the numeric return value for the operation, - and the second element is a string value for the error. - A ``0`` numeric error means no error in the operation. + ``USERPWD <username>:<password>`` + .. versionadded:: 3.7 -``TIMEOUT <seconds>`` - Terminate the operation after a given total time has elapsed. + Set username and password for operation. -``USERPWD <username>:<password>`` - .. versionadded:: 3.7 + ``HTTPHEADER <HTTP-header>`` + .. versionadded:: 3.7 - Set username and password for operation. + HTTP header for ``DOWNLOAD`` and ``UPLOAD`` operations. ``HTTPHEADER`` + can be repeated for multiple options: -``HTTPHEADER <HTTP-header>`` - .. versionadded:: 3.7 + .. code-block:: cmake - HTTP header for ``DOWNLOAD`` and ``UPLOAD`` operations. ``HTTPHEADER`` can be - repeated for multiple options: + file(DOWNLOAD <url> + HTTPHEADER "Authorization: Bearer <auth-token>" + HTTPHEADER "UserAgent: Mozilla/5.0") - .. code-block:: cmake + ``NETRC <level>`` + .. versionadded:: 3.11 - file(DOWNLOAD <url> - HTTPHEADER "Authorization: Bearer <auth-token>" - HTTPHEADER "UserAgent: Mozilla/5.0") - -``NETRC <level>`` - .. versionadded:: 3.11 - - Specify whether the .netrc file is to be used for operation. If this - option is not specified, the value of the :variable:`CMAKE_NETRC` variable - will be used instead. - Valid levels are: - - ``IGNORED`` - The .netrc file is ignored. - This is the default. - ``OPTIONAL`` - The .netrc file is optional, and information in the URL is preferred. - The file will be scanned to find which ever information is not specified - in the URL. - ``REQUIRED`` - The .netrc file is required, and information in the URL is ignored. - -``NETRC_FILE <file>`` - .. versionadded:: 3.11 - - Specify an alternative .netrc file to the one in your home directory, - if the ``NETRC`` level is ``OPTIONAL`` or ``REQUIRED``. If this option - is not specified, the value of the :variable:`CMAKE_NETRC_FILE` variable will - be used instead. - -``TLS_VERIFY <ON|OFF>`` - Specify whether to verify the server certificate for ``https://`` URLs. - The default is to *not* verify. If this option is not specified, the value - of the :variable:`CMAKE_TLS_VERIFY` variable will be used instead. + Specify whether the .netrc file is to be used for operation. If this + option is not specified, the value of the :variable:`CMAKE_NETRC` + variable will be used instead. - .. versionadded:: 3.18 - Added support to ``file(UPLOAD)``. + Valid levels are: -``TLS_CAINFO <file>`` - Specify a custom Certificate Authority file for ``https://`` URLs. If this - option is not specified, the value of the :variable:`CMAKE_TLS_CAINFO` - variable will be used instead. + ``IGNORED`` + The .netrc file is ignored. + This is the default. - .. versionadded:: 3.18 - Added support to ``file(UPLOAD)``. + ``OPTIONAL`` + The .netrc file is optional, and information in the URL is preferred. + The file will be scanned to find which ever information is not + specified in the URL. -For ``https://`` URLs CMake must be built with OpenSSL support. ``TLS/SSL`` -certificates are not checked by default. Set ``TLS_VERIFY`` to ``ON`` to -check certificates. + ``REQUIRED`` + The .netrc file is required, and information in the URL is ignored. -Additional options to ``DOWNLOAD`` are: + ``NETRC_FILE <file>`` + .. versionadded:: 3.11 -``EXPECTED_HASH ALGO=<value>`` + Specify an alternative .netrc file to the one in your home directory, + if the ``NETRC`` level is ``OPTIONAL`` or ``REQUIRED``. If this option + is not specified, the value of the :variable:`CMAKE_NETRC_FILE` variable + will be used instead. - Verify that the downloaded content hash matches the expected value, where - ``ALGO`` is one of the algorithms supported by ``file(<HASH>)``. - If the file already exists and matches the hash, the download is skipped. - If the file already exists and does not match the hash, the file is - downloaded again. If after download the file does not match the hash, the - operation fails with an error. It is an error to specify this option if - ``DOWNLOAD`` is not given a ``<file>``. + ``TLS_VERIFY <ON|OFF>`` + Specify whether to verify the server certificate for ``https://`` URLs. + The default is to *not* verify. If this option is not specified, the + value of the :variable:`CMAKE_TLS_VERIFY` variable will be used instead. -``EXPECTED_MD5 <value>`` - Historical short-hand for ``EXPECTED_HASH MD5=<value>``. It is an error to - specify this if ``DOWNLOAD`` is not given a ``<file>``. + .. versionadded:: 3.18 + Added support to ``file(UPLOAD)``. -``RANGE_START <value>`` - .. versionadded:: 3.24 + ``TLS_CAINFO <file>`` + Specify a custom Certificate Authority file for ``https://`` URLs. + If this option is not specified, the value of the + :variable:`CMAKE_TLS_CAINFO` variable will be used instead. - Offset of the start of the range in file in bytes. Could be omitted to - download up to the specified ``RANGE_END``. + .. versionadded:: 3.18 + Added support to ``file(UPLOAD)``. -``RANGE_END <value>`` - .. versionadded:: 3.24 + For ``https://`` URLs CMake must be built with OpenSSL support. ``TLS/SSL`` + certificates are not checked by default. Set ``TLS_VERIFY`` to ``ON`` to + check certificates. - Offset of the end of the range in file in bytes. Could be omitted to - download everything from the specified ``RANGE_START`` to the end of file. + Additional options to ``DOWNLOAD`` are: -Locking -^^^^^^^ + ``EXPECTED_HASH <algorithm>=<value>`` + Verify that the downloaded content hash matches the expected value, where + ``<algorithm>`` is one of the algorithms supported by :cref:`<HASH>`. + If the file already exists and matches the hash, the download is skipped. + If the file already exists and does not match the hash, the file is + downloaded again. If after download the file does not match the hash, the + operation fails with an error. It is an error to specify this option if + ``DOWNLOAD`` is not given a ``<file>``. + + ``EXPECTED_MD5 <value>`` + Historical short-hand for ``EXPECTED_HASH MD5=<value>``. It is an error + to specify this if ``DOWNLOAD`` is not given a ``<file>``. -.. _LOCK: + ``RANGE_START <value>`` + .. versionadded:: 3.24 -.. code-block:: cmake + Offset of the start of the range in file in bytes. Could be omitted to + download up to the specified ``RANGE_END``. + ``RANGE_END <value>`` + .. versionadded:: 3.24 + + Offset of the end of the range in file in bytes. Could be omitted to + download everything from the specified ``RANGE_START`` to the end of + file. + +Locking +^^^^^^^ + +.. signature:: file(LOCK <path> [DIRECTORY] [RELEASE] [GUARD <FUNCTION|FILE|PROCESS>] [RESULT_VARIABLE <variable>] [TIMEOUT <seconds>]) -.. versionadded:: 3.2 - -Lock a file specified by ``<path>`` if no ``DIRECTORY`` option present and file -``<path>/cmake.lock`` otherwise. File will be locked for scope defined by -``GUARD`` option (default value is ``PROCESS``). ``RELEASE`` option can be used -to unlock file explicitly. If option ``TIMEOUT`` is not specified CMake will -wait until lock succeed or until fatal error occurs. If ``TIMEOUT`` is set to -``0`` lock will be tried once and result will be reported immediately. If -``TIMEOUT`` is not ``0`` CMake will try to lock file for the period specified -by ``<seconds>`` value. Any errors will be interpreted as fatal if there is no -``RESULT_VARIABLE`` option. Otherwise result will be stored in ``<variable>`` -and will be ``0`` on success or error message on failure. - -Note that lock is advisory - there is no guarantee that other processes will -respect this lock, i.e. lock synchronize two or more CMake instances sharing -some modifiable resources. Similar logic applied to ``DIRECTORY`` option - -locking parent directory doesn't prevent other ``LOCK`` commands to lock any -child directory or file. - -Trying to lock file twice is not allowed. Any intermediate directories and -file itself will be created if they not exist. ``GUARD`` and ``TIMEOUT`` -options ignored on ``RELEASE`` operation. + .. versionadded:: 3.2 + + Lock a file specified by ``<path>`` if no ``DIRECTORY`` option present and + file ``<path>/cmake.lock`` otherwise. The file will be locked for the scope + defined by the ``GUARD`` option (default value is ``PROCESS``). The + ``RELEASE`` option can be used to unlock the file explicitly. If the + ``TIMEOUT`` option is not specified, CMake will wait until the lock succeeds + or until a fatal error occurs. If ``TIMEOUT`` is set to ``0``, locking will + be tried once and the result will be reported immediately. If ``TIMEOUT`` + is not ``0``, CMake will try to lock the file for the period specified by + the ``TIMEOUT <seconds>`` value. Any errors will be interpreted as fatal if + there is no ``RESULT_VARIABLE`` option. Otherwise, the result will be stored + in ``<variable>`` and will be ``0`` on success or an error message on + failure. + + Note that lock is advisory; there is no guarantee that other processes will + respect this lock, i.e. lock synchronize two or more CMake instances sharing + some modifiable resources. Similar logic applies to the ``DIRECTORY`` option; + locking a parent directory doesn't prevent other ``LOCK`` commands from + locking any child directory or file. + + Trying to lock the same file twice is not allowed. Any intermediate + directories and the file itself will be created if they not exist. The + ``GUARD`` and ``TIMEOUT`` options are ignored on the ``RELEASE`` operation. Archiving ^^^^^^^^^ -.. _ARCHIVE_CREATE: - -.. code-block:: cmake - +.. signature:: file(ARCHIVE_CREATE OUTPUT <archive> PATHS <paths>... [FORMAT <format>] - [COMPRESSION <compression> [COMPRESSION_LEVEL <compression-level>]] + [COMPRESSION <compression> + [COMPRESSION_LEVEL <compression-level>]] [MTIME <mtime>] [VERBOSE]) + :target: ARCHIVE_CREATE + :break: verbatim -.. versionadded:: 3.18 - -Creates the specified ``<archive>`` file with the files and directories -listed in ``<paths>``. Note that ``<paths>`` must list actual files or -directories, wildcards are not supported. - -Use the ``FORMAT`` option to specify the archive format. Supported values -for ``<format>`` are ``7zip``, ``gnutar``, ``pax``, ``paxr``, ``raw`` and -``zip``. If ``FORMAT`` is not given, the default format is ``paxr``. + .. versionadded:: 3.18 -Some archive formats allow the type of compression to be specified. -The ``7zip`` and ``zip`` archive formats already imply a specific type of -compression. The other formats use no compression by default, but can be -directed to do so with the ``COMPRESSION`` option. Valid values for -``<compression>`` are ``None``, ``BZip2``, ``GZip``, ``XZ``, and ``Zstd``. + Creates the specified ``<archive>`` file with the files and directories + listed in ``<paths>``. Note that ``<paths>`` must list actual files or + directories; wildcards are not supported. -.. versionadded:: 3.19 - The compression level can be specified with the ``COMPRESSION_LEVEL`` option. - The ``<compression-level>`` should be between 0-9, with the default being 0. - The ``COMPRESSION`` option must be present when ``COMPRESSION_LEVEL`` is given. + Use the ``FORMAT`` option to specify the archive format. Supported values + for ``<format>`` are ``7zip``, ``gnutar``, ``pax``, ``paxr``, ``raw`` and + ``zip``. If ``FORMAT`` is not given, the default format is ``paxr``. -.. versionadded:: 3.26 - The ``<compression-level>`` of the ``Zstd`` algorithm can be set between 0-19. + Some archive formats allow the type of compression to be specified. + The ``7zip`` and ``zip`` archive formats already imply a specific type of + compression. The other formats use no compression by default, but can be + directed to do so with the ``COMPRESSION`` option. Valid values for + ``<compression>`` are ``None``, ``BZip2``, ``GZip``, ``XZ``, and ``Zstd``. -.. note:: - With ``FORMAT`` set to ``raw`` only one file will be compressed with the - compression type specified by ``COMPRESSION``. + .. versionadded:: 3.19 + The compression level can be specified with the ``COMPRESSION_LEVEL`` + option. The ``<compression-level>`` should be between 0-9, with the + default being 0. The ``COMPRESSION`` option must be present when + ``COMPRESSION_LEVEL`` is given. -The ``VERBOSE`` option enables verbose output for the archive operation. + .. versionadded:: 3.26 + The ``<compression-level>`` of the ``Zstd`` algorithm can be set + between 0-19. -To specify the modification time recorded in tarball entries, use -the ``MTIME`` option. + .. note:: + With ``FORMAT`` set to ``raw``, only one file will be compressed with the + compression type specified by ``COMPRESSION``. -.. _ARCHIVE_EXTRACT: + The ``VERBOSE`` option enables verbose output for the archive operation. -.. code-block:: cmake + To specify the modification time recorded in tarball entries, use + the ``MTIME`` option. - file(ARCHIVE_EXTRACT INPUT <archive> +.. signature:: + file(ARCHIVE_EXTRACT + INPUT <archive> [DESTINATION <dir>] [PATTERNS <patterns>...] [LIST_ONLY] [VERBOSE] [TOUCH]) + :target: ARCHIVE_EXTRACT -.. versionadded:: 3.18 + .. versionadded:: 3.18 -Extracts or lists the content of the specified ``<archive>``. + Extracts or lists the content of the specified ``<archive>``. -The directory where the content of the archive will be extracted to can -be specified using the ``DESTINATION`` option. If the directory does not -exist, it will be created. If ``DESTINATION`` is not given, the current -binary directory will be used. + The directory where the content of the archive will be extracted to can + be specified using the ``DESTINATION`` option. If the directory does not + exist, it will be created. If ``DESTINATION`` is not given, the current + binary directory will be used. -If required, you may select which files and directories to list or extract -from the archive using the specified ``<patterns>``. Wildcards are supported. -If the ``PATTERNS`` option is not given, the entire archive will be listed or -extracted. + If required, you may select which files and directories to list or extract + from the archive using the specified ``<patterns>``. Wildcards are + supported. If the ``PATTERNS`` option is not given, the entire archive will + be listed or extracted. -``LIST_ONLY`` will list the files in the archive rather than extract them. + ``LIST_ONLY`` will list the files in the archive rather than extract them. -.. versionadded:: 3.24 - The ``TOUCH`` option gives extracted files a current local - timestamp instead of extracting file timestamps from the archive. + .. versionadded:: 3.24 + The ``TOUCH`` option gives extracted files a current local + timestamp instead of extracting file timestamps from the archive. -With ``VERBOSE``, the command will produce verbose output. + With ``VERBOSE``, the command will produce verbose output. diff --git a/Help/command/get_filename_component.rst b/Help/command/get_filename_component.rst index 899ede6..7d74a33 100644 --- a/Help/command/get_filename_component.rst +++ b/Help/command/get_filename_component.rst @@ -4,9 +4,9 @@ get_filename_component Get a specific component of a full filename. .. versionchanged:: 3.20 - This command has been superseded by :command:`cmake_path` command, except - ``REALPATH`` now offered by :ref:`file(REAL_PATH)<REAL_PATH>` command and - ``PROGRAM`` now available in :command:`separate_arguments(PROGRAM)` command. + This command has been superseded by the :command:`cmake_path` command, except + for ``REALPATH``, which is now offered by :command:`file(REAL_PATH)`, and + ``PROGRAM``, now available in :command:`separate_arguments(PROGRAM)`. .. versionchanged:: 3.24 The undocumented feature offering the capability to query the ``Windows`` diff --git a/Help/command/if.rst b/Help/command/if.rst index 684c113..be855e1 100644 --- a/Help/command/if.rst +++ b/Help/command/if.rst @@ -39,7 +39,7 @@ the ``if``, ``elseif`` and :command:`while` clauses. Compound conditions are evaluated in the following order of precedence: -1. Parentheses. +1. `Parentheses`_. 2. Unary tests such as `EXISTS`_, `COMMAND`_, and `DEFINED`_. @@ -57,262 +57,284 @@ Compound conditions are evaluated in the following order of precedence: Basic Expressions """"""""""""""""" -``if(<constant>)`` - True if the constant is ``1``, ``ON``, ``YES``, ``TRUE``, ``Y``, - or a non-zero number (including floating point numbers). - False if the constant is ``0``, ``OFF``, - ``NO``, ``FALSE``, ``N``, ``IGNORE``, ``NOTFOUND``, the empty string, - or ends in the suffix ``-NOTFOUND``. Named boolean constants are - case-insensitive. If the argument is not one of these specific - constants, it is treated as a variable or string (see `Variable Expansion`_ - further below) and one of the following two forms applies. - -``if(<variable>)`` - True if given a variable that is defined to a value that is not a false - constant. False otherwise, including if the variable is undefined. - Note that macro arguments are not variables. - :ref:`Environment Variables <CMake Language Environment Variables>` also - cannot be tested this way, e.g. ``if(ENV{some_var})`` will always evaluate - to false. - -``if(<string>)`` - A quoted string always evaluates to false unless: - - * The string's value is one of the true constants, or - * Policy :policy:`CMP0054` is not set to ``NEW`` and the string's value - happens to be a variable name that is affected by :policy:`CMP0054`'s - behavior. +.. signature:: if(<constant>) + :target: constant + + True if the constant is ``1``, ``ON``, ``YES``, ``TRUE``, ``Y``, + or a non-zero number (including floating point numbers). + False if the constant is ``0``, ``OFF``, + ``NO``, ``FALSE``, ``N``, ``IGNORE``, ``NOTFOUND``, the empty string, + or ends in the suffix ``-NOTFOUND``. Named boolean constants are + case-insensitive. If the argument is not one of these specific + constants, it is treated as a variable or string (see `Variable Expansion`_ + further below) and one of the following two forms applies. + +.. signature:: if(<variable>) + :target: variable + + True if given a variable that is defined to a value that is not a false + constant. False otherwise, including if the variable is undefined. + Note that macro arguments are not variables. + :ref:`Environment Variables <CMake Language Environment Variables>` also + cannot be tested this way, e.g. ``if(ENV{some_var})`` will always evaluate + to false. + +.. signature:: if(<string>) + :target: string + + A quoted string always evaluates to false unless: + + * The string's value is one of the true constants, or + * Policy :policy:`CMP0054` is not set to ``NEW`` and the string's value + happens to be a variable name that is affected by :policy:`CMP0054`'s + behavior. Logic Operators """"""""""""""" -.. _NOT: +.. signature:: if(NOT <condition>) + + True if the condition is not true. -``if(NOT <condition>)`` - True if the condition is not true. +.. signature:: if(<cond1> AND <cond2>) + :target: AND -.. _AND: + True if both conditions would be considered true individually. -``if(<cond1> AND <cond2>)`` - True if both conditions would be considered true individually. +.. signature:: if(<cond1> OR <cond2>) + :target: OR -.. _OR: + True if either condition would be considered true individually. -``if(<cond1> OR <cond2>)`` - True if either condition would be considered true individually. +.. signature:: if((condition) AND (condition OR (condition))) + :target: parentheses -``if((condition) AND (condition OR (condition)))`` - The conditions inside the parenthesis are evaluated first and then - the remaining condition is evaluated as in the other examples. - Where there are nested parenthesis the innermost are evaluated as part - of evaluating the condition that contains them. + The conditions inside the parenthesis are evaluated first and then + the remaining condition is evaluated as in the other examples. + Where there are nested parenthesis the innermost are evaluated as part + of evaluating the condition that contains them. Existence Checks """""""""""""""" -.. _COMMAND: +.. signature:: if(COMMAND <command-name>) + + True if the given name is a command, macro or function that can be + invoked. + +.. signature:: if(POLICY <policy-id>) + + True if the given name is an existing policy (of the form ``CMP<NNNN>``). -``if(COMMAND command-name)`` - True if the given name is a command, macro or function that can be - invoked. +.. signature:: if(TARGET <target-name>) -``if(POLICY policy-id)`` - True if the given name is an existing policy (of the form ``CMP<NNNN>``). + True if the given name is an existing logical target name created + by a call to the :command:`add_executable`, :command:`add_library`, + or :command:`add_custom_target` command that has already been invoked + (in any directory). -``if(TARGET target-name)`` - True if the given name is an existing logical target name created - by a call to the :command:`add_executable`, :command:`add_library`, - or :command:`add_custom_target` command that has already been invoked - (in any directory). +.. signature:: if(TEST <test-name>) + + .. versionadded:: 3.3 -``if(TEST test-name)`` - .. versionadded:: 3.3 True if the given name is an existing test name created by the :command:`add_test` command. -.. _DEFINED: +.. signature:: if(DEFINED <name>|CACHE{<name>}|ENV{<name>}) -``if(DEFINED <name>|CACHE{<name>}|ENV{<name>})`` - True if a variable, cache variable or environment variable - with given ``<name>`` is defined. The value of the variable - does not matter. Note the following caveats: + True if a variable, cache variable or environment variable + with given ``<name>`` is defined. The value of the variable + does not matter. Note the following caveats: - * Macro arguments are not variables. - * It is not possible to test directly whether a `<name>` is a non-cache - variable. The expression ``if(DEFINED someName)`` will evaluate to true - if either a cache or non-cache variable ``someName`` exists. In - comparison, the expression ``if(DEFINED CACHE{someName})`` will only - evaluate to true if a cache variable ``someName`` exists. Both expressions - need to be tested if you need to know whether a non-cache variable exists: - ``if(DEFINED someName AND NOT DEFINED CACHE{someName})``. + * Macro arguments are not variables. + * It is not possible to test directly whether a `<name>` is a non-cache + variable. The expression ``if(DEFINED someName)`` will evaluate to true + if either a cache or non-cache variable ``someName`` exists. In + comparison, the expression ``if(DEFINED CACHE{someName})`` will only + evaluate to true if a cache variable ``someName`` exists. Both expressions + need to be tested if you need to know whether a non-cache variable exists: + ``if(DEFINED someName AND NOT DEFINED CACHE{someName})``. .. versionadded:: 3.14 Added support for ``CACHE{<name>}`` variables. -``if(<variable|string> IN_LIST <variable>)`` - .. versionadded:: 3.3 +.. signature:: if(<variable|string> IN_LIST <variable>) + :target: IN_LIST + + .. versionadded:: 3.3 + True if the given element is contained in the named list variable. File Operations """"""""""""""" -.. _EXISTS: +.. signature:: if(EXISTS <path-to-file-or-directory>) + + True if the named file or directory exists. Behavior is well-defined + only for explicit full paths (a leading ``~/`` is not expanded as + a home directory and is considered a relative path). + Resolves symbolic links, i.e. if the named file or directory is a + symbolic link, returns true if the target of the symbolic link exists. + + False if the given path is an empty string. -``if(EXISTS path-to-file-or-directory)`` - True if the named file or directory exists. Behavior is well-defined - only for explicit full paths (a leading ``~/`` is not expanded as - a home directory and is considered a relative path). - Resolves symbolic links, i.e. if the named file or directory is a - symbolic link, returns true if the target of the symbolic link exists. +.. signature:: if(<file1> IS_NEWER_THAN <file2>) + :target: IS_NEWER_THAN - False if the given path is an empty string. + True if ``file1`` is newer than ``file2`` or if one of the two files doesn't + exist. Behavior is well-defined only for full paths. If the file + time stamps are exactly the same, an ``IS_NEWER_THAN`` comparison returns + true, so that any dependent build operations will occur in the event + of a tie. This includes the case of passing the same file name for + both file1 and file2. -``if(file1 IS_NEWER_THAN file2)`` - True if ``file1`` is newer than ``file2`` or if one of the two files doesn't - exist. Behavior is well-defined only for full paths. If the file - time stamps are exactly the same, an ``IS_NEWER_THAN`` comparison returns - true, so that any dependent build operations will occur in the event - of a tie. This includes the case of passing the same file name for - both file1 and file2. +.. signature:: if(IS_DIRECTORY <path>) -``if(IS_DIRECTORY path)`` - True if ``path`` is a directory. Behavior is well-defined only - for full paths. + True if ``path`` is a directory. Behavior is well-defined only + for full paths. - False if the given path is an empty string. + False if the given path is an empty string. -``if(IS_SYMLINK file-name)`` - True if the given name is a symbolic link. Behavior is well-defined - only for full paths. +.. signature:: if(IS_SYMLINK <path>) -``if(IS_ABSOLUTE path)`` - True if the given path is an absolute path. Note the following special - cases: + True if the given path is a symbolic link. Behavior is well-defined + only for full paths. - * An empty ``path`` evaluates to false. - * On Windows hosts, any ``path`` that begins with a drive letter and colon - (e.g. ``C:``), a forward slash or a backslash will evaluate to true. - This means a path like ``C:no\base\dir`` will evaluate to true, even - though the non-drive part of the path is relative. - * On non-Windows hosts, any ``path`` that begins with a tilde (``~``) - evaluates to true. +.. signature:: if(IS_ABSOLUTE <path>) + + True if the given path is an absolute path. Note the following special + cases: + + * An empty ``path`` evaluates to false. + * On Windows hosts, any ``path`` that begins with a drive letter and colon + (e.g. ``C:``), a forward slash or a backslash will evaluate to true. + This means a path like ``C:no\base\dir`` will evaluate to true, even + though the non-drive part of the path is relative. + * On non-Windows hosts, any ``path`` that begins with a tilde (``~``) + evaluates to true. Comparisons """"""""""" -.. _MATCHES: +.. signature:: if(<variable|string> MATCHES <regex>) + :target: MATCHES -``if(<variable|string> MATCHES regex)`` - True if the given string or variable's value matches the given regular - expression. See :ref:`Regex Specification` for regex format. + True if the given string or variable's value matches the given regular + expression. See :ref:`Regex Specification` for regex format. - .. versionadded:: 3.9 - ``()`` groups are captured in :variable:`CMAKE_MATCH_<n>` variables. + .. versionadded:: 3.9 + ``()`` groups are captured in :variable:`CMAKE_MATCH_<n>` variables. -.. _LESS: +.. signature:: if(<variable|string> LESS <variable|string>) + :target: LESS -``if(<variable|string> LESS <variable|string>)`` - True if the given string or variable's value is a valid number and less - than that on the right. + True if the given string or variable's value is a valid number and less + than that on the right. -.. _GREATER: +.. signature:: if(<variable|string> GREATER <variable|string>) + :target: GREATER + + True if the given string or variable's value is a valid number and greater + than that on the right. -``if(<variable|string> GREATER <variable|string>)`` - True if the given string or variable's value is a valid number and greater - than that on the right. +.. signature:: if(<variable|string> EQUAL <variable|string>) + :target: EQUAL -.. _EQUAL: + True if the given string or variable's value is a valid number and equal + to that on the right. -``if(<variable|string> EQUAL <variable|string>)`` - True if the given string or variable's value is a valid number and equal - to that on the right. +.. signature:: if(<variable|string> LESS_EQUAL <variable|string>) + :target: LESS_EQUAL -.. _LESS_EQUAL: + .. versionadded:: 3.7 -``if(<variable|string> LESS_EQUAL <variable|string>)`` - .. versionadded:: 3.7 True if the given string or variable's value is a valid number and less than or equal to that on the right. -.. _GREATER_EQUAL: +.. signature:: if(<variable|string> GREATER_EQUAL <variable|string>) + :target: GREATER_EQUAL + + .. versionadded:: 3.7 -``if(<variable|string> GREATER_EQUAL <variable|string>)`` - .. versionadded:: 3.7 True if the given string or variable's value is a valid number and greater than or equal to that on the right. -.. _STRLESS: +.. signature:: if(<variable|string> STRLESS <variable|string>) + :target: STRLESS -``if(<variable|string> STRLESS <variable|string>)`` - True if the given string or variable's value is lexicographically less - than the string or variable on the right. + True if the given string or variable's value is lexicographically less + than the string or variable on the right. -.. _STRGREATER: +.. signature:: if(<variable|string> STRGREATER <variable|string>) + :target: STRGREATER -``if(<variable|string> STRGREATER <variable|string>)`` - True if the given string or variable's value is lexicographically greater - than the string or variable on the right. + True if the given string or variable's value is lexicographically greater + than the string or variable on the right. -.. _STREQUAL: +.. signature:: if(<variable|string> STREQUAL <variable|string>) + :target: STREQUAL -``if(<variable|string> STREQUAL <variable|string>)`` - True if the given string or variable's value is lexicographically equal - to the string or variable on the right. + True if the given string or variable's value is lexicographically equal + to the string or variable on the right. -.. _STRLESS_EQUAL: +.. signature:: if(<variable|string> STRLESS_EQUAL <variable|string>) + :target: STRLESS_EQUAL + + .. versionadded:: 3.7 -``if(<variable|string> STRLESS_EQUAL <variable|string>)`` - .. versionadded:: 3.7 True if the given string or variable's value is lexicographically less than or equal to the string or variable on the right. -.. _STRGREATER_EQUAL: +.. signature:: if(<variable|string> STRGREATER_EQUAL <variable|string>) + :target: STRGREATER_EQUAL + + .. versionadded:: 3.7 -``if(<variable|string> STRGREATER_EQUAL <variable|string>)`` - .. versionadded:: 3.7 True if the given string or variable's value is lexicographically greater than or equal to the string or variable on the right. Version Comparisons """"""""""""""""""" -.. _VERSION_LESS: +.. signature:: if(<variable|string> VERSION_LESS <variable|string>) + :target: VERSION_LESS -``if(<variable|string> VERSION_LESS <variable|string>)`` - Component-wise integer version number comparison (version format is - ``major[.minor[.patch[.tweak]]]``, omitted components are treated as zero). - Any non-integer version component or non-integer trailing part of a version - component effectively truncates the string at that point. + Component-wise integer version number comparison (version format is + ``major[.minor[.patch[.tweak]]]``, omitted components are treated as zero). + Any non-integer version component or non-integer trailing part of a version + component effectively truncates the string at that point. -.. _VERSION_GREATER: +.. signature:: if(<variable|string> VERSION_GREATER <variable|string>) + :target: VERSION_GREATER -``if(<variable|string> VERSION_GREATER <variable|string>)`` - Component-wise integer version number comparison (version format is - ``major[.minor[.patch[.tweak]]]``, omitted components are treated as zero). - Any non-integer version component or non-integer trailing part of a version - component effectively truncates the string at that point. + Component-wise integer version number comparison (version format is + ``major[.minor[.patch[.tweak]]]``, omitted components are treated as zero). + Any non-integer version component or non-integer trailing part of a version + component effectively truncates the string at that point. -.. _VERSION_EQUAL: +.. signature:: if(<variable|string> VERSION_EQUAL <variable|string>) + :target: VERSION_EQUAL -``if(<variable|string> VERSION_EQUAL <variable|string>)`` - Component-wise integer version number comparison (version format is - ``major[.minor[.patch[.tweak]]]``, omitted components are treated as zero). - Any non-integer version component or non-integer trailing part of a version - component effectively truncates the string at that point. + Component-wise integer version number comparison (version format is + ``major[.minor[.patch[.tweak]]]``, omitted components are treated as zero). + Any non-integer version component or non-integer trailing part of a version + component effectively truncates the string at that point. -.. _VERSION_LESS_EQUAL: +.. signature:: if(<variable|string> VERSION_LESS_EQUAL <variable|string>) + :target: VERSION_LESS_EQUAL + + .. versionadded:: 3.7 -``if(<variable|string> VERSION_LESS_EQUAL <variable|string>)`` - .. versionadded:: 3.7 Component-wise integer version number comparison (version format is ``major[.minor[.patch[.tweak]]]``, omitted components are treated as zero). Any non-integer version component or non-integer trailing part of a version component effectively truncates the string at that point. -.. _VERSION_GREATER_EQUAL: +.. signature:: if(<variable|string> VERSION_GREATER_EQUAL <variable|string>) + :target: VERSION_GREATER_EQUAL + + .. versionadded:: 3.7 -``if(<variable|string> VERSION_GREATER_EQUAL <variable|string>)`` - .. versionadded:: 3.7 Component-wise integer version number comparison (version format is ``major[.minor[.patch[.tweak]]]``, omitted components are treated as zero). Any non-integer version component or non-integer trailing part of a version @@ -321,9 +343,9 @@ Version Comparisons Path Comparisons """""""""""""""" -.. _PATH_EQUAL: +.. signature:: if(<variable|string> PATH_EQUAL <variable|string>) + :target: PATH_EQUAL -``if(<variable|string> PATH_EQUAL <variable|string>)`` .. versionadded:: 3.24 Compares the two paths component-by-component. Only if every component of @@ -386,35 +408,35 @@ constant. Automatic evaluation applies in the other cases whenever the above-documented condition syntax accepts ``<variable|string>``: -* The left hand argument to ``MATCHES`` is first checked to see if it is - a defined variable, if so the variable's value is used, otherwise the +* The left hand argument to `MATCHES`_ is first checked to see if it is + a defined variable. If so, the variable's value is used, otherwise the original value is used. -* If the left hand argument to ``MATCHES`` is missing it returns false +* If the left hand argument to `MATCHES`_ is missing it returns false without error -* Both left and right hand arguments to ``LESS``, ``GREATER``, ``EQUAL``, - ``LESS_EQUAL``, and ``GREATER_EQUAL``, are independently tested to see if - they are defined variables, if so their defined values are used otherwise +* Both left and right hand arguments to `LESS`_, `GREATER`_, `EQUAL`_, + `LESS_EQUAL`_, and `GREATER_EQUAL`_, are independently tested to see if + they are defined variables. If so, their defined values are used otherwise the original value is used. -* Both left and right hand arguments to ``STRLESS``, ``STRGREATER``, - ``STREQUAL``, ``STRLESS_EQUAL``, and ``STRGREATER_EQUAL`` are independently - tested to see if they are defined variables, if so their defined values are +* Both left and right hand arguments to `STRLESS`_, `STRGREATER`_, + `STREQUAL`_, `STRLESS_EQUAL`_, and `STRGREATER_EQUAL`_ are independently + tested to see if they are defined variables. If so, their defined values are used otherwise the original value is used. -* Both left and right hand arguments to ``VERSION_LESS``, - ``VERSION_GREATER``, ``VERSION_EQUAL``, ``VERSION_LESS_EQUAL``, and - ``VERSION_GREATER_EQUAL`` are independently tested to see if they are defined - variables, if so their defined values are used otherwise the original value +* Both left and right hand arguments to `VERSION_LESS`_, + `VERSION_GREATER`_, `VERSION_EQUAL`_, `VERSION_LESS_EQUAL`_, and + `VERSION_GREATER_EQUAL`_ are independently tested to see if they are defined + variables. If so, their defined values are used otherwise the original value is used. -* The right hand argument to ``NOT`` is tested to see if it is a boolean - constant, if so the value is used, otherwise it is assumed to be a +* The right hand argument to `NOT`_ is tested to see if it is a boolean + constant. If so, the value is used, otherwise it is assumed to be a variable and it is dereferenced. -* The left and right hand arguments to ``AND`` and ``OR`` are independently - tested to see if they are boolean constants, if so they are used as +* The left and right hand arguments to `AND`_ and `OR`_ are independently + tested to see if they are boolean constants. If so, they are used as such, otherwise they are assumed to be variables and are dereferenced. .. versionchanged:: 3.1 diff --git a/Help/command/list.rst b/Help/command/list.rst index 33c4f80..191003a 100644 --- a/Help/command/list.rst +++ b/Help/command/list.rst @@ -36,23 +36,25 @@ Synopsis Introduction ^^^^^^^^^^^^ -The list subcommands ``APPEND``, ``INSERT``, ``FILTER``, ``PREPEND``, -``POP_BACK``, ``POP_FRONT``, ``REMOVE_AT``, ``REMOVE_ITEM``, -``REMOVE_DUPLICATES``, ``REVERSE`` and ``SORT`` may create -new values for the list within the current CMake variable scope. Similar to -the :command:`set` command, the LIST command creates new variable values in -the current scope, even if the list itself is actually defined in a parent -scope. To propagate the results of these operations upwards, use -:command:`set` with ``PARENT_SCOPE``, :command:`set` with -``CACHE INTERNAL``, or some other means of value propagation. +The list subcommands :cref:`APPEND`, :cref:`INSERT`, :cref:`FILTER`, +:cref:`PREPEND`, :cref:`POP_BACK`, :cref:`POP_FRONT`, :cref:`REMOVE_AT`, +:cref:`REMOVE_ITEM`, :cref:`REMOVE_DUPLICATES`, :cref:`REVERSE` and +:cref:`SORT` may create new values for the list within the current CMake +variable scope. Similar to the :command:`set` command, the ``list`` command +creates new variable values in the current scope, even if the list itself is +actually defined in a parent scope. To propagate the results of these +operations upwards, use :command:`set` with ``PARENT_SCOPE``, +:command:`set` with ``CACHE INTERNAL``, or some other means of value +propagation. .. note:: A list in cmake is a ``;`` separated group of strings. To create a - list the set command can be used. For example, ``set(var a b c d e)`` - creates a list with ``a;b;c;d;e``, and ``set(var "a b c d e")`` creates a - string or a list with one item in it. (Note macro arguments are not - variables, and therefore cannot be used in LIST commands.) + list, the :command:`set` command can be used. For example, + ``set(var a b c d e)`` creates a list with ``a;b;c;d;e``, and + ``set(var "a b c d e")`` creates a string or a list with one item in it. + (Note that macro arguments are not variables, and therefore cannot be used + in ``LIST`` commands.) .. note:: @@ -66,76 +68,54 @@ scope. To propagate the results of these operations upwards, use Reading ^^^^^^^ -.. _LENGTH: - -.. code-block:: cmake - +.. signature:: list(LENGTH <list> <output variable>) -Returns the list's length. - -.. _GET: - -.. code-block:: cmake + Returns the list's length. +.. signature:: list(GET <list> <element index> [<element index> ...] <output variable>) -Returns the list of elements specified by indices from the list. - -.. _JOIN: + Returns the list of elements specified by indices from the list. -.. code-block:: cmake +.. signature:: list(JOIN <list> <glue> <output variable>) - list(JOIN <list> <glue> <output variable>) + .. versionadded:: 3.12 -.. versionadded:: 3.12 - -Returns a string joining all list's elements using the glue string. -To join multiple strings, which are not part of a list, use ``JOIN`` operator -from :command:`string` command. - -.. _SUBLIST: - -.. code-block:: cmake + Returns a string joining all list's elements using the glue string. + To join multiple strings, which are not part of a list, + use :command:`string(JOIN)`. +.. signature:: list(SUBLIST <list> <begin> <length> <output variable>) -.. versionadded:: 3.12 + .. versionadded:: 3.12 -Returns a sublist of the given list. -If ``<length>`` is 0, an empty list will be returned. -If ``<length>`` is -1 or the list is smaller than ``<begin>+<length>`` then -the remaining elements of the list starting at ``<begin>`` will be returned. + Returns a sublist of the given list. + If ``<length>`` is 0, an empty list will be returned. + If ``<length>`` is -1 or the list is smaller than ``<begin>+<length>`` then + the remaining elements of the list starting at ``<begin>`` will be returned. Search ^^^^^^ -.. _FIND: - -.. code-block:: cmake - +.. signature:: list(FIND <list> <value> <output variable>) -Returns the index of the element specified in the list or -1 -if it wasn't found. + Returns the index of the element specified in the list + or ``-1`` if it wasn't found. Modification ^^^^^^^^^^^^ -.. _APPEND: - -.. code-block:: cmake - +.. signature:: list(APPEND <list> [<element> ...]) -Appends elements to the list. If no variable named ``<list>`` exists in the -current scope its value is treated as empty and the elements are appended to -that empty list. - -.. _FILTER: - -.. code-block:: cmake + Appends elements to the list. If no variable named ``<list>`` exists in the + current scope its value is treated as empty and the elements are appended to + that empty list. +.. signature:: list(FILTER <list> <INCLUDE|EXCLUDE> REGEX <regular_expression>) .. versionadded:: 3.6 @@ -146,219 +126,205 @@ In ``REGEX`` mode, items will be matched against the given regular expression. For more information on regular expressions look under :ref:`string(REGEX) <Regex Specification>`. -.. _INSERT: - -.. code-block:: cmake - +.. signature:: list(INSERT <list> <element_index> <element> [<element> ...]) -Inserts elements to the list to the specified index. It is an -error to specify an out-of-range index. Valid indexes are 0 to `N` -where `N` is the length of the list, inclusive. An empty list -has length 0. If no variable named ``<list>`` exists in the -current scope its value is treated as empty and the elements are -inserted in that empty list. - -.. _POP_BACK: - -.. code-block:: cmake + Inserts elements to the list to the specified index. It is an + error to specify an out-of-range index. Valid indexes are 0 to `N` + where `N` is the length of the list, inclusive. An empty list + has length 0. If no variable named ``<list>`` exists in the + current scope its value is treated as empty and the elements are + inserted in that empty list. +.. signature:: list(POP_BACK <list> [<out-var>...]) -.. versionadded:: 3.15 + .. versionadded:: 3.15 -If no variable name is given, removes exactly one element. Otherwise, -with `N` variable names provided, assign the last `N` elements' values -to the given variables and then remove the last `N` values from -``<list>``. - -.. _POP_FRONT: - -.. code-block:: cmake + If no variable name is given, removes exactly one element. Otherwise, + with `N` variable names provided, assign the last `N` elements' values + to the given variables and then remove the last `N` values from + ``<list>``. +.. signature:: list(POP_FRONT <list> [<out-var>...]) -.. versionadded:: 3.15 - -If no variable name is given, removes exactly one element. Otherwise, -with `N` variable names provided, assign the first `N` elements' values -to the given variables and then remove the first `N` values from -``<list>``. + .. versionadded:: 3.15 -.. _PREPEND: - -.. code-block:: cmake + If no variable name is given, removes exactly one element. Otherwise, + with `N` variable names provided, assign the first `N` elements' values + to the given variables and then remove the first `N` values from + ``<list>``. +.. signature:: list(PREPEND <list> [<element> ...]) -.. versionadded:: 3.15 - -Insert elements to the 0th position in the list. If no variable named -``<list>`` exists in the current scope its value is treated as empty and -the elements are prepended to that empty list. + .. versionadded:: 3.15 -.. _REMOVE_ITEM: - -.. code-block:: cmake + Insert elements to the 0th position in the list. If no variable named + ``<list>`` exists in the current scope its value is treated as empty and + the elements are prepended to that empty list. +.. signature:: list(REMOVE_ITEM <list> <value> [<value> ...]) -Removes all instances of the given items from the list. - -.. _REMOVE_AT: - -.. code-block:: cmake + Removes all instances of the given items from the list. +.. signature:: list(REMOVE_AT <list> <index> [<index> ...]) -Removes items at given indices from the list. - -.. _REMOVE_DUPLICATES: - -.. code-block:: cmake + Removes items at given indices from the list. +.. signature:: list(REMOVE_DUPLICATES <list>) -Removes duplicated items in the list. The relative order of items is preserved, -but if duplicates are encountered, only the first instance is preserved. - -.. _TRANSFORM: - -.. code-block:: cmake + Removes duplicated items in the list. The relative order of items + is preserved, but if duplicates are encountered, + only the first instance is preserved. +.. signature:: list(TRANSFORM <list> <ACTION> [<SELECTOR>] - [OUTPUT_VARIABLE <output variable>]) + [OUTPUT_VARIABLE <output variable>]) -.. versionadded:: 3.12 + .. versionadded:: 3.12 -Transforms the list by applying an action to all or, by specifying a -``<SELECTOR>``, to the selected elements of the list, storing the result -in-place or in the specified output variable. + Transforms the list by applying an action to all or, by specifying a + ``<SELECTOR>``, to the selected elements of the list, storing the result + in-place or in the specified output variable. -.. note:: + .. note:: - The ``TRANSFORM`` sub-command does not change the number of elements in the - list. If a ``<SELECTOR>`` is specified, only some elements will be changed, - the other ones will remain the same as before the transformation. + The ``TRANSFORM`` sub-command does not change the number of elements in the + list. If a ``<SELECTOR>`` is specified, only some elements will be changed, + the other ones will remain the same as before the transformation. -``<ACTION>`` specifies the action to apply to the elements of the list. -The actions have exactly the same semantics as sub-commands of the -:command:`string` command. ``<ACTION>`` must be one of the following: + ``<ACTION>`` specifies the action to apply to the elements of the list. + The actions have exactly the same semantics as sub-commands of the + :command:`string` command. ``<ACTION>`` must be one of the following: -``APPEND``, ``PREPEND``: Append, prepend specified value to each element of -the list. + :command:`APPEND <string(APPEND)>`, :command:`PREPEND <string(PREPEND)>` + Append, prepend specified value to each element of the list. - .. code-block:: cmake + .. code-block:: cmake - list(TRANSFORM <list> <APPEND|PREPEND> <value> ...) + list(TRANSFORM <list> <APPEND|PREPEND> <value> ...) -``TOUPPER``, ``TOLOWER``: Convert each element of the list to upper, lower -characters. + :command:`TOUPPER <string(TOUPPER)>`, :command:`TOLOWER <string(TOLOWER)>` + Convert each element of the list to upper, lower characters. - .. code-block:: cmake + .. code-block:: cmake - list(TRANSFORM <list> <TOLOWER|TOUPPER> ...) + list(TRANSFORM <list> <TOLOWER|TOUPPER> ...) -``STRIP``: Remove leading and trailing spaces from each element of the -list. + :command:`STRIP <string(STRIP)>` + Remove leading and trailing spaces from each element of the list. - .. code-block:: cmake + .. code-block:: cmake - list(TRANSFORM <list> STRIP ...) + list(TRANSFORM <list> STRIP ...) -``GENEX_STRIP``: Strip any -:manual:`generator expressions <cmake-generator-expressions(7)>` from each -element of the list. + :command:`GENEX_STRIP <string(GENEX_STRIP)>` + Strip any + :manual:`generator expressions <cmake-generator-expressions(7)>` + from each element of the list. - .. code-block:: cmake + .. code-block:: cmake - list(TRANSFORM <list> GENEX_STRIP ...) + list(TRANSFORM <list> GENEX_STRIP ...) -``REPLACE``: Match the regular expression as many times as possible and -substitute the replacement expression for the match for each element -of the list -(Same semantic as ``REGEX REPLACE`` from :command:`string` command). + :command:`REPLACE <string(REGEX REPLACE)>`: + Match the regular expression as many times as possible and substitute + the replacement expression for the match for each element of the list + (same semantic as :command:`string(REGEX REPLACE)`). - .. code-block:: cmake + .. code-block:: cmake - list(TRANSFORM <list> REPLACE <regular_expression> - <replace_expression> ...) + list(TRANSFORM <list> REPLACE <regular_expression> + <replace_expression> ...) -``<SELECTOR>`` determines which elements of the list will be transformed. -Only one type of selector can be specified at a time. When given, -``<SELECTOR>`` must be one of the following: + ``<SELECTOR>`` determines which elements of the list will be transformed. + Only one type of selector can be specified at a time. + When given, ``<SELECTOR>`` must be one of the following: -``AT``: Specify a list of indexes. + ``AT`` + Specify a list of indexes. - .. code-block:: cmake + .. code-block:: cmake - list(TRANSFORM <list> <ACTION> AT <index> [<index> ...] ...) + list(TRANSFORM <list> <ACTION> AT <index> [<index> ...] ...) -``FOR``: Specify a range with, optionally, an increment used to iterate over -the range. + ``FOR`` + Specify a range with, optionally, + an increment used to iterate over the range. - .. code-block:: cmake + .. code-block:: cmake - list(TRANSFORM <list> <ACTION> FOR <start> <stop> [<step>] ...) + list(TRANSFORM <list> <ACTION> FOR <start> <stop> [<step>] ...) -``REGEX``: Specify a regular expression. Only elements matching the regular -expression will be transformed. + ``REGEX`` + Specify a regular expression. + Only elements matching the regular expression will be transformed. - .. code-block:: cmake + .. code-block:: cmake - list(TRANSFORM <list> <ACTION> REGEX <regular_expression> ...) + list(TRANSFORM <list> <ACTION> REGEX <regular_expression> ...) Ordering ^^^^^^^^ -.. _REVERSE: +.. signature:: + list(REVERSE <list>) -.. code-block:: cmake + Reverses the contents of the list in-place. - list(REVERSE <list>) +.. signature:: + list(SORT <list> [COMPARE <compare>] [CASE <case>] [ORDER <order>]) -Reverses the contents of the list in-place. + Sorts the list in-place alphabetically. -.. _SORT: + .. versionadded:: 3.13 + Added the ``COMPARE``, ``CASE``, and ``ORDER`` options. -.. code-block:: cmake + .. versionadded:: 3.18 + Added the ``COMPARE NATURAL`` option. - list(SORT <list> [COMPARE <compare>] [CASE <case>] [ORDER <order>]) + Use the ``COMPARE`` keyword to select the comparison method for sorting. + The ``<compare>`` option should be one of: -Sorts the list in-place alphabetically. + ``STRING`` + Sorts a list of strings alphabetically. + This is the default behavior if the ``COMPARE`` option is not given. -.. versionadded:: 3.13 - Added the ``COMPARE``, ``CASE``, and ``ORDER`` options. + ``FILE_BASENAME`` + Sorts a list of pathnames of files by their basenames. -.. versionadded:: 3.18 - Added the ``COMPARE NATURAL`` option. + ``NATURAL`` + Sorts a list of strings using natural order + (see ``strverscmp(3)`` manual), i.e. such that contiguous digits + are compared as whole numbers. + For example: the following list `10.0 1.1 2.1 8.0 2.0 3.1` + will be sorted as `1.1 2.0 2.1 3.1 8.0 10.0` if the ``NATURAL`` + comparison is selected where it will be sorted as + `1.1 10.0 2.0 2.1 3.1 8.0` with the ``STRING`` comparison. -Use the ``COMPARE`` keyword to select the comparison method for sorting. -The ``<compare>`` option should be one of: + Use the ``CASE`` keyword to select a case sensitive or case insensitive + sort mode. The ``<case>`` option should be one of: -* ``STRING``: Sorts a list of strings alphabetically. This is the - default behavior if the ``COMPARE`` option is not given. -* ``FILE_BASENAME``: Sorts a list of pathnames of files by their basenames. -* ``NATURAL``: Sorts a list of strings using natural order - (see ``strverscmp(3)`` manual), i.e. such that contiguous digits - are compared as whole numbers. - For example: the following list `10.0 1.1 2.1 8.0 2.0 3.1` - will be sorted as `1.1 2.0 2.1 3.1 8.0 10.0` if the ``NATURAL`` - comparison is selected where it will be sorted as - `1.1 10.0 2.0 2.1 3.1 8.0` with the ``STRING`` comparison. + ``SENSITIVE`` + List items are sorted in a case-sensitive manner. + This is the default behavior if the ``CASE`` option is not given. -Use the ``CASE`` keyword to select a case sensitive or case insensitive -sort mode. The ``<case>`` option should be one of: + ``INSENSITIVE`` + List items are sorted case insensitively. The order of + items which differ only by upper/lowercase is not specified. -* ``SENSITIVE``: List items are sorted in a case-sensitive manner. This is - the default behavior if the ``CASE`` option is not given. -* ``INSENSITIVE``: List items are sorted case insensitively. The order of - items which differ only by upper/lowercase is not specified. + To control the sort order, the ``ORDER`` keyword can be given. + The ``<order>`` option should be one of: -To control the sort order, the ``ORDER`` keyword can be given. -The ``<order>`` option should be one of: + ``ASCENDING`` + Sorts the list in ascending order. + This is the default behavior when the ``ORDER`` option is not given. -* ``ASCENDING``: Sorts the list in ascending order. This is the default - behavior when the ``ORDER`` option is not given. -* ``DESCENDING``: Sorts the list in descending order. + ``DESCENDING`` + Sorts the list in descending order. diff --git a/Help/command/set.rst b/Help/command/set.rst index c724844..aeb88b3 100644 --- a/Help/command/set.rst +++ b/Help/command/set.rst @@ -8,109 +8,119 @@ and cache entries. Signatures of this command that specify a ``<value>...`` placeholder expect zero or more arguments. Multiple arguments will be joined as -a :ref:`semicolon-separated list <CMake Language Lists>` to form the actual variable -value to be set. Zero arguments will cause normal variables to be -unset. See the :command:`unset` command to unset variables explicitly. +a :ref:`semicolon-separated list <CMake Language Lists>` to form the +actual variable value to be set. Set Normal Variable ^^^^^^^^^^^^^^^^^^^ -.. code-block:: cmake - +.. signature:: set(<variable> <value>... [PARENT_SCOPE]) + :target: normal + + Set or unset ``<variable>`` in the current function or directory scope: + + * If at least one ``<value>...`` is given, set the variable to that value. + * If no value is given, unset the variable. This is equivalent to + :command:`unset(<variable>) <unset>`. -Sets the given ``<variable>`` in the current function or directory scope. + If the ``PARENT_SCOPE`` option is given the variable will be set in + the scope above the current scope. Each new directory or :command:`function` + command creates a new scope. A scope can also be created with the + :command:`block` command. This command will set the value of a variable into + the parent directory, calling function or encompassing scope (whichever is + applicable to the case at hand). The previous state of the variable's value + stays the same in the current scope (e.g., if it was undefined before, it is + still undefined and if it had a value, it is still that value). -If the ``PARENT_SCOPE`` option is given the variable will be set in -the scope above the current scope. Each new directory or :command:`function` -command creates a new scope. A scope can also be created with the -:command:`block` command. This command will set the value of a variable into -the parent directory, calling function or encompassing scope (whichever is -applicable to the case at hand). The previous state of the variable's value -stays the same in the current scope (e.g., if it was undefined before, it is -still undefined and if it had a value, it is still that value). + The :command:`block(PROPAGATE)` and :command:`return(PROPAGATE)` commands + can be used as an alternate method to the :command:`set(PARENT_SCOPE)` + and :command:`unset(PARENT_SCOPE)` commands to update the parent scope. -The :command:`block(PROPAGATE)` and :command:`return(PROPAGATE)` commands can -be used as an alternate method to the :command:`set(PARENT_SCOPE)` and -:command:`unset(PARENT_SCOPE)` commands to update the parent scope. +.. include:: UNSET_NOTE.txt Set Cache Entry ^^^^^^^^^^^^^^^ -.. code-block:: cmake - +.. signature:: set(<variable> <value>... CACHE <type> <docstring> [FORCE]) - -Sets the given cache ``<variable>`` (cache entry). Since cache entries -are meant to provide user-settable values this does not overwrite -existing cache entries by default. Use the ``FORCE`` option to -overwrite existing entries. - -The ``<type>`` must be specified as one of: - -``BOOL`` - Boolean ``ON/OFF`` value. :manual:`cmake-gui(1)` offers a checkbox. - -``FILEPATH`` - Path to a file on disk. :manual:`cmake-gui(1)` offers a file dialog. - -``PATH`` - Path to a directory on disk. :manual:`cmake-gui(1)` offers a file dialog. - -``STRING`` - A line of text. :manual:`cmake-gui(1)` offers a text field or a - drop-down selection if the :prop_cache:`STRINGS` cache entry - property is set. - -``INTERNAL`` - A line of text. :manual:`cmake-gui(1)` does not show internal entries. - They may be used to store variables persistently across runs. - Use of this type implies ``FORCE``. - -The ``<docstring>`` must be specified as a line of text providing -a quick summary of the option for presentation to :manual:`cmake-gui(1)` -users. - -If the cache entry does not exist prior to the call or the ``FORCE`` -option is given then the cache entry will be set to the given value. - -.. note:: - - The content of the cache variable will not be directly accessible if a normal - variable of the same name already exists (see :ref:`rules of variable - evaluation <CMake Language Variables>`). If policy :policy:`CMP0126` is set - to ``OLD``, any normal variable binding in the current scope will be removed. - -It is possible for the cache entry to exist prior to the call but -have no type set if it was created on the :manual:`cmake(1)` command -line by a user through the :option:`-D\<var\>=\<value\> <cmake -D>` option without -specifying a type. In this case the ``set`` command will add the -type. Furthermore, if the ``<type>`` is ``PATH`` or ``FILEPATH`` -and the ``<value>`` provided on the command line is a relative path, -then the ``set`` command will treat the path as relative to the -current working directory and convert it to an absolute path. + :target: CACHE + + Sets the given cache ``<variable>`` (cache entry). Since cache entries + are meant to provide user-settable values this does not overwrite + existing cache entries by default. Use the ``FORCE`` option to + overwrite existing entries. + + The ``<type>`` must be specified as one of: + + ``BOOL`` + Boolean ``ON/OFF`` value. + :manual:`cmake-gui(1)` offers a checkbox. + + ``FILEPATH`` + Path to a file on disk. + :manual:`cmake-gui(1)` offers a file dialog. + + ``PATH`` + Path to a directory on disk. + :manual:`cmake-gui(1)` offers a file dialog. + + ``STRING`` + A line of text. + :manual:`cmake-gui(1)` offers a text field or a drop-down selection + if the :prop_cache:`STRINGS` cache entry property is set. + + ``INTERNAL`` + A line of text. + :manual:`cmake-gui(1)` does not show internal entries. + They may be used to store variables persistently across runs. + Use of this type implies ``FORCE``. + + The ``<docstring>`` must be specified as a line of text + providing a quick summary of the option + for presentation to :manual:`cmake-gui(1)` users. + + If the cache entry does not exist prior to the call or the ``FORCE`` + option is given then the cache entry will be set to the given value. + + .. note:: + + The content of the cache variable will not be directly accessible + if a normal variable of the same name already exists + (see :ref:`rules of variable evaluation <CMake Language Variables>`). + If policy :policy:`CMP0126` is set to ``OLD``, any normal variable + binding in the current scope will be removed. + + It is possible for the cache entry to exist prior to the call but + have no type set if it was created on the :manual:`cmake(1)` command + line by a user through the :option:`-D\<var\>=\<value\> <cmake -D>` option + without specifying a type. In this case the ``set`` command will add the + type. Furthermore, if the ``<type>`` is ``PATH`` or ``FILEPATH`` + and the ``<value>`` provided on the command line is a relative path, + then the ``set`` command will treat the path as relative to the + current working directory and convert it to an absolute path. Set Environment Variable ^^^^^^^^^^^^^^^^^^^^^^^^ -.. code-block:: cmake - +.. signature:: set(ENV{<variable>} [<value>]) + :target: ENV -Sets an :manual:`Environment Variable <cmake-env-variables(7)>` -to the given value. -Subsequent calls of ``$ENV{<variable>}`` will return this new value. + Sets an :manual:`Environment Variable <cmake-env-variables(7)>` + to the given value. + Subsequent calls of ``$ENV{<variable>}`` will return this new value. -This command affects only the current CMake process, not the process -from which CMake was called, nor the system environment at large, -nor the environment of subsequent build or test processes. + This command affects only the current CMake process, not the process + from which CMake was called, nor the system environment at large, + nor the environment of subsequent build or test processes. -If no argument is given after ``ENV{<variable>}`` or if ``<value>`` is -an empty string, then this command will clear any existing value of the -environment variable. + If no argument is given after ``ENV{<variable>}`` or if ``<value>`` is + an empty string, then this command will clear any existing value of the + environment variable. -Arguments after ``<value>`` are ignored. If extra arguments are found, -then an author warning is issued. + Arguments after ``<value>`` are ignored. If extra arguments are found, + then an author warning is issued. See Also ^^^^^^^^ diff --git a/Help/command/string.rst b/Help/command/string.rst index c24b9bc..e226aa1 100644 --- a/Help/command/string.rst +++ b/Help/command/string.rst @@ -32,7 +32,7 @@ Synopsis string(`COMPARE`_ <op> <string1> <string2> <out-var>) `Hashing`_ - string(`\<HASH\> <HASH_>`_ <out-var> <input>) + string(`\<HASH\>`_ <out-var> <input>) `Generation`_ string(`ASCII`_ <number>... <out-var>) @@ -45,16 +45,16 @@ Synopsis `JSON`_ string(JSON <out-var> [ERROR_VARIABLE <error-var>] - {:ref:`GET <JSON_GET>` | :ref:`TYPE <JSON_TYPE>` | :ref:`LENGTH <JSON_LENGTH>` | :ref:`REMOVE <JSON_REMOVE>`} + {`GET <JSON GET_>`_ | `TYPE <JSON TYPE_>`_ | `LENGTH <JSON LENGTH_>`_ | `REMOVE <JSON REMOVE_>`_} <json-string> <member|index> [<member|index> ...]) string(JSON <out-var> [ERROR_VARIABLE <error-var>] - :ref:`MEMBER <JSON_MEMBER>` <json-string> + `MEMBER <JSON MEMBER_>`_ <json-string> [<member|index> ...] <index>) string(JSON <out-var> [ERROR_VARIABLE <error-var>] - :ref:`SET <JSON_SET>` <json-string> + `SET <JSON SET_>`_ <json-string> <member|index> [<member|index> ...] <value>) string(JSON <out-var> [ERROR_VARIABLE <error-var>] - :ref:`EQUAL <JSON_EQUAL>` <json-string1> <json-string2>) + `EQUAL <JSON EQUAL_>`_ <json-string1> <json-string2>) Search and Replace ^^^^^^^^^^^^^^^^^^ @@ -62,75 +62,60 @@ Search and Replace Search and Replace With Plain Strings """"""""""""""""""""""""""""""""""""" -.. _FIND: - -.. code-block:: cmake - +.. signature:: string(FIND <string> <substring> <output_variable> [REVERSE]) -Return the position where the given ``<substring>`` was found in -the supplied ``<string>``. If the ``REVERSE`` flag was used, the command will -search for the position of the last occurrence of the specified -``<substring>``. If the ``<substring>`` is not found, a position of -1 is -returned. - -The ``string(FIND)`` subcommand treats all strings as ASCII-only characters. -The index stored in ``<output_variable>`` will also be counted in bytes, -so strings containing multi-byte characters may lead to unexpected results. + Return the position where the given ``<substring>`` was found in + the supplied ``<string>``. If the ``REVERSE`` flag was used, the command + will search for the position of the last occurrence of the specified + ``<substring>``. If the ``<substring>`` is not found, a position of -1 is + returned. -.. _REPLACE: - -.. code-block:: cmake + The ``string(FIND)`` subcommand treats all strings as ASCII-only characters. + The index stored in ``<output_variable>`` will also be counted in bytes, + so strings containing multi-byte characters may lead to unexpected results. +.. signature:: string(REPLACE <match_string> <replace_string> <output_variable> <input> [<input>...]) -Replace all occurrences of ``<match_string>`` in the ``<input>`` -with ``<replace_string>`` and store the result in the ``<output_variable>``. + Replace all occurrences of ``<match_string>`` in the ``<input>`` + with ``<replace_string>`` and store the result in the ``<output_variable>``. Search and Replace With Regular Expressions """"""""""""""""""""""""""""""""""""""""""" -.. _`REGEX MATCH`: - -.. code-block:: cmake - +.. signature:: string(REGEX MATCH <regular_expression> <output_variable> <input> [<input>...]) -Match the ``<regular_expression>`` once and store the match in the -``<output_variable>``. -All ``<input>`` arguments are concatenated before matching. -Regular expressions are specified in the subsection just below. - -.. _`REGEX MATCHALL`: - -.. code-block:: cmake + Match the ``<regular_expression>`` once and store the match in the + ``<output_variable>``. + All ``<input>`` arguments are concatenated before matching. + Regular expressions are specified in the subsection just below. +.. signature:: string(REGEX MATCHALL <regular_expression> <output_variable> <input> [<input>...]) -Match the ``<regular_expression>`` as many times as possible and store the -matches in the ``<output_variable>`` as a list. -All ``<input>`` arguments are concatenated before matching. - -.. _`REGEX REPLACE`: - -.. code-block:: cmake + Match the ``<regular_expression>`` as many times as possible and store the + matches in the ``<output_variable>`` as a list. + All ``<input>`` arguments are concatenated before matching. +.. signature:: string(REGEX REPLACE <regular_expression> <replacement_expression> <output_variable> <input> [<input>...]) -Match the ``<regular_expression>`` as many times as possible and substitute -the ``<replacement_expression>`` for the match in the output. -All ``<input>`` arguments are concatenated before matching. + Match the ``<regular_expression>`` as many times as possible and substitute + the ``<replacement_expression>`` for the match in the output. + All ``<input>`` arguments are concatenated before matching. -The ``<replacement_expression>`` may refer to parenthesis-delimited -subexpressions of the match using ``\1``, ``\2``, ..., ``\9``. Note that -two backslashes (``\\1``) are required in CMake code to get a backslash -through argument parsing. + The ``<replacement_expression>`` may refer to parenthesis-delimited + subexpressions of the match using ``\1``, ``\2``, ..., ``\9``. Note that + two backslashes (``\\1``) are required in CMake code to get a backslash + through argument parsing. .. _`Regex Specification`: @@ -201,130 +186,100 @@ newlines, and backslashes (respectively) to pass in a regex. For example: Manipulation ^^^^^^^^^^^^ -.. _APPEND: - -.. code-block:: cmake - +.. signature:: string(APPEND <string_variable> [<input>...]) -.. versionadded:: 3.4 - -Append all the ``<input>`` arguments to the string. + .. versionadded:: 3.4 -.. _PREPEND: - -.. code-block:: cmake + Append all the ``<input>`` arguments to the string. +.. signature:: string(PREPEND <string_variable> [<input>...]) -.. versionadded:: 3.10 - -Prepend all the ``<input>`` arguments to the string. - -.. _CONCAT: + .. versionadded:: 3.10 -.. code-block:: cmake + Prepend all the ``<input>`` arguments to the string. +.. signature:: string(CONCAT <output_variable> [<input>...]) -Concatenate all the ``<input>`` arguments together and store -the result in the named ``<output_variable>``. - -.. _JOIN: - -.. code-block:: cmake + Concatenate all the ``<input>`` arguments together and store + the result in the named ``<output_variable>``. +.. signature:: string(JOIN <glue> <output_variable> [<input>...]) -.. versionadded:: 3.12 - -Join all the ``<input>`` arguments together using the ``<glue>`` -string and store the result in the named ``<output_variable>``. - -To join a list's elements, prefer to use the ``JOIN`` operator -from the :command:`list` command. This allows for the elements to have -special characters like ``;`` in them. + .. versionadded:: 3.12 -.. _TOLOWER: + Join all the ``<input>`` arguments together using the ``<glue>`` + string and store the result in the named ``<output_variable>``. -.. code-block:: cmake + To join a list's elements, prefer to use the ``JOIN`` operator + from the :command:`list` command. This allows for the elements to have + special characters like ``;`` in them. +.. signature:: string(TOLOWER <string> <output_variable>) -Convert ``<string>`` to lower characters. - -.. _TOUPPER: - -.. code-block:: cmake + Convert ``<string>`` to lower characters. +.. signature:: string(TOUPPER <string> <output_variable>) -Convert ``<string>`` to upper characters. - -.. _LENGTH: - -.. code-block:: cmake + Convert ``<string>`` to upper characters. +.. signature:: string(LENGTH <string> <output_variable>) -Store in an ``<output_variable>`` a given string's length in bytes. -Note that this means if ``<string>`` contains multi-byte characters, the -result stored in ``<output_variable>`` will *not* be the number of characters. - -.. _SUBSTRING: - -.. code-block:: cmake + Store in an ``<output_variable>`` a given string's length in bytes. + Note that this means if ``<string>`` contains multi-byte characters, + the result stored in ``<output_variable>`` will *not* be + the number of characters. +.. signature:: string(SUBSTRING <string> <begin> <length> <output_variable>) -Store in an ``<output_variable>`` a substring of a given ``<string>``. If -``<length>`` is ``-1`` the remainder of the string starting at ``<begin>`` -will be returned. - -.. versionchanged:: 3.2 - If ``<string>`` is shorter than ``<length>`` then the end of the string - is used instead. Previous versions of CMake reported an error in this case. - -Both ``<begin>`` and ``<length>`` are counted in bytes, so care must -be exercised if ``<string>`` could contain multi-byte characters. + Store in an ``<output_variable>`` a substring of a given ``<string>``. If + ``<length>`` is ``-1`` the remainder of the string starting at ``<begin>`` + will be returned. -.. _STRIP: + .. versionchanged:: 3.2 + If ``<string>`` is shorter than ``<length>`` + then the end of the string is used instead. + Previous versions of CMake reported an error in this case. -.. code-block:: cmake + Both ``<begin>`` and ``<length>`` are counted in bytes, so care must + be exercised if ``<string>`` could contain multi-byte characters. +.. signature:: string(STRIP <string> <output_variable>) -Store in an ``<output_variable>`` a substring of a given ``<string>`` with -leading and trailing spaces removed. - -.. _GENEX_STRIP: - -.. code-block:: cmake + Store in an ``<output_variable>`` a substring of a given ``<string>`` + with leading and trailing spaces removed. +.. signature:: string(GENEX_STRIP <string> <output_variable>) -.. versionadded:: 3.1 - -Strip any :manual:`generator expressions <cmake-generator-expressions(7)>` -from the input ``<string>`` and store the result in the ``<output_variable>``. - -.. _REPEAT: + .. versionadded:: 3.1 -.. code-block:: cmake + Strip any :manual:`generator expressions <cmake-generator-expressions(7)>` + from the input ``<string>`` and store the result + in the ``<output_variable>``. +.. signature:: string(REPEAT <string> <count> <output_variable>) -.. versionadded:: 3.15 + .. versionadded:: 3.15 -Produce the output string as the input ``<string>`` repeated ``<count>`` times. + Produce the output string as the input ``<string>`` + repeated ``<count>`` times. Comparison ^^^^^^^^^^ .. _COMPARE: -.. code-block:: cmake - +.. signature:: string(COMPARE LESS <string1> <string2> <output_variable>) string(COMPARE GREATER <string1> <string2> <output_variable>) string(COMPARE EQUAL <string1> <string2> <output_variable>) @@ -332,240 +287,217 @@ Comparison string(COMPARE LESS_EQUAL <string1> <string2> <output_variable>) string(COMPARE GREATER_EQUAL <string1> <string2> <output_variable>) -Compare the strings and store true or false in the ``<output_variable>``. + Compare the strings and store true or false in the ``<output_variable>``. -.. versionadded:: 3.7 - Added the ``LESS_EQUAL`` and ``GREATER_EQUAL`` options. + .. versionadded:: 3.7 + Added the ``LESS_EQUAL`` and ``GREATER_EQUAL`` options. .. _`Supported Hash Algorithms`: Hashing ^^^^^^^ -.. _`HASH`: - -.. code-block:: cmake - +.. signature:: string(<HASH> <output_variable> <input>) + :target: <HASH> + + Compute a cryptographic hash of the ``<input>`` string. + The supported ``<HASH>`` algorithm names are: + + ``MD5`` + Message-Digest Algorithm 5, RFC 1321. + ``SHA1`` + US Secure Hash Algorithm 1, RFC 3174. + ``SHA224`` + US Secure Hash Algorithms, RFC 4634. + ``SHA256`` + US Secure Hash Algorithms, RFC 4634. + ``SHA384`` + US Secure Hash Algorithms, RFC 4634. + ``SHA512`` + US Secure Hash Algorithms, RFC 4634. + ``SHA3_224`` + Keccak SHA-3. + ``SHA3_256`` + Keccak SHA-3. + ``SHA3_384`` + Keccak SHA-3. + ``SHA3_512`` + Keccak SHA-3. -Compute a cryptographic hash of the ``<input>`` string. -The supported ``<HASH>`` algorithm names are: - -``MD5`` - Message-Digest Algorithm 5, RFC 1321. -``SHA1`` - US Secure Hash Algorithm 1, RFC 3174. -``SHA224`` - US Secure Hash Algorithms, RFC 4634. -``SHA256`` - US Secure Hash Algorithms, RFC 4634. -``SHA384`` - US Secure Hash Algorithms, RFC 4634. -``SHA512`` - US Secure Hash Algorithms, RFC 4634. -``SHA3_224`` - Keccak SHA-3. -``SHA3_256`` - Keccak SHA-3. -``SHA3_384`` - Keccak SHA-3. -``SHA3_512`` - Keccak SHA-3. - -.. versionadded:: 3.8 - Added the ``SHA3_*`` hash algorithms. + .. versionadded:: 3.8 + Added the ``SHA3_*`` hash algorithms. Generation ^^^^^^^^^^ -.. _ASCII: - -.. code-block:: cmake - +.. signature:: string(ASCII <number> [<number> ...] <output_variable>) -Convert all numbers into corresponding ASCII characters. - -.. _HEX: - -.. code-block:: cmake + Convert all numbers into corresponding ASCII characters. +.. signature:: string(HEX <string> <output_variable>) -.. versionadded:: 3.18 - -Convert each byte in the input ``<string>`` to its hexadecimal representation -and store the concatenated hex digits in the ``<output_variable>``. Letters in -the output (``a`` through ``f``) are in lowercase. + .. versionadded:: 3.18 -.. _CONFIGURE: - -.. code-block:: cmake + Convert each byte in the input ``<string>`` to its hexadecimal representation + and store the concatenated hex digits in the ``<output_variable>``. + Letters in the output (``a`` through ``f``) are in lowercase. +.. signature:: string(CONFIGURE <string> <output_variable> [@ONLY] [ESCAPE_QUOTES]) -Transform a ``<string>`` like :command:`configure_file` transforms a file. - -.. _MAKE_C_IDENTIFIER: - -.. code-block:: cmake + Transform a ``<string>`` like :command:`configure_file` transforms a file. +.. signature:: string(MAKE_C_IDENTIFIER <string> <output_variable>) -Convert each non-alphanumeric character in the input ``<string>`` to an -underscore and store the result in the ``<output_variable>``. If the first -character of the ``<string>`` is a digit, an underscore will also be prepended -to the result. - -.. _RANDOM: - -.. code-block:: cmake + Convert each non-alphanumeric character in the input ``<string>`` to an + underscore and store the result in the ``<output_variable>``. If the first + character of the ``<string>`` is a digit, an underscore will also be + prepended to the result. +.. signature:: string(RANDOM [LENGTH <length>] [ALPHABET <alphabet>] [RANDOM_SEED <seed>] <output_variable>) -Return a random string of given ``<length>`` consisting of -characters from the given ``<alphabet>``. Default length is 5 characters -and default alphabet is all numbers and upper and lower case letters. -If an integer ``RANDOM_SEED`` is given, its value will be used to seed the -random number generator. - -.. _TIMESTAMP: - -.. code-block:: cmake + Return a random string of given ``<length>`` consisting of + characters from the given ``<alphabet>``. Default length is 5 characters + and default alphabet is all numbers and upper and lower case letters. + If an integer ``RANDOM_SEED`` is given, its value will be used to seed the + random number generator. +.. signature:: string(TIMESTAMP <output_variable> [<format_string>] [UTC]) -Write a string representation of the current date -and/or time to the ``<output_variable>``. - -If the command is unable to obtain a timestamp, the ``<output_variable>`` -will be set to the empty string ``""``. + Write a string representation of the current date + and/or time to the ``<output_variable>``. -The optional ``UTC`` flag requests the current date/time representation to -be in Coordinated Universal Time (UTC) rather than local time. + If the command is unable to obtain a timestamp, the ``<output_variable>`` + will be set to the empty string ``""``. -The optional ``<format_string>`` may contain the following format -specifiers: - -``%%`` - .. versionadded:: 3.8 + The optional ``UTC`` flag requests the current date/time representation to + be in Coordinated Universal Time (UTC) rather than local time. - A literal percent sign (%). + The optional ``<format_string>`` may contain the following format + specifiers: -``%d`` - The day of the current month (01-31). + ``%%`` + .. versionadded:: 3.8 -``%H`` - The hour on a 24-hour clock (00-23). + A literal percent sign (%). -``%I`` - The hour on a 12-hour clock (01-12). + ``%d`` + The day of the current month (01-31). -``%j`` - The day of the current year (001-366). + ``%H`` + The hour on a 24-hour clock (00-23). -``%m`` - The month of the current year (01-12). + ``%I`` + The hour on a 12-hour clock (01-12). -``%b`` - .. versionadded:: 3.7 + ``%j`` + The day of the current year (001-366). - Abbreviated month name (e.g. Oct). + ``%m`` + The month of the current year (01-12). -``%B`` - .. versionadded:: 3.10 + ``%b`` + .. versionadded:: 3.7 - Full month name (e.g. October). + Abbreviated month name (e.g. Oct). -``%M`` - The minute of the current hour (00-59). + ``%B`` + .. versionadded:: 3.10 -``%s`` - .. versionadded:: 3.6 + Full month name (e.g. October). - Seconds since midnight (UTC) 1-Jan-1970 (UNIX time). + ``%M`` + The minute of the current hour (00-59). -``%S`` - The second of the current minute. 60 represents a leap second. (00-60) + ``%s`` + .. versionadded:: 3.6 -``%f`` - .. versionadded:: 3.23 + Seconds since midnight (UTC) 1-Jan-1970 (UNIX time). - The microsecond of the current second (000000-999999). + ``%S`` + The second of the current minute. 60 represents a leap second. (00-60) -``%U`` - The week number of the current year (00-53). + ``%f`` + .. versionadded:: 3.23 -``%V`` - .. versionadded:: 3.22 + The microsecond of the current second (000000-999999). - The ISO 8601 week number of the current year (01-53). + ``%U`` + The week number of the current year (00-53). -``%w`` - The day of the current week. 0 is Sunday. (0-6) + ``%V`` + .. versionadded:: 3.22 -``%a`` - .. versionadded:: 3.7 + The ISO 8601 week number of the current year (01-53). - Abbreviated weekday name (e.g. Fri). + ``%w`` + The day of the current week. 0 is Sunday. (0-6) -``%A`` - .. versionadded:: 3.10 + ``%a`` + .. versionadded:: 3.7 - Full weekday name (e.g. Friday). + Abbreviated weekday name (e.g. Fri). -``%y`` - The last two digits of the current year (00-99). + ``%A`` + .. versionadded:: 3.10 -``%Y`` - The current year. + Full weekday name (e.g. Friday). -``%z`` - .. versionadded:: 3.26 + ``%y`` + The last two digits of the current year (00-99). - The offset of the time zone from UTC, in hours and minutes, - with format ``+hhmm`` or ``-hhmm``. + ``%Y`` + The current year. -``%Z`` - .. versionadded:: 3.26 + ``%z`` + .. versionadded:: 3.26 - The time zone name. + The offset of the time zone from UTC, in hours and minutes, + with format ``+hhmm`` or ``-hhmm``. -Unknown format specifiers will be ignored and copied to the output -as-is. + ``%Z`` + .. versionadded:: 3.26 -If no explicit ``<format_string>`` is given, it will default to: + The time zone name. -:: + Unknown format specifiers will be ignored and copied to the output + as-is. - %Y-%m-%dT%H:%M:%S for local time. - %Y-%m-%dT%H:%M:%SZ for UTC. + If no explicit ``<format_string>`` is given, it will default to: -.. versionadded:: 3.8 - If the ``SOURCE_DATE_EPOCH`` environment variable is set, - its value will be used instead of the current time. - See https://reproducible-builds.org/specs/source-date-epoch/ for details. + :: -.. _UUID: + %Y-%m-%dT%H:%M:%S for local time. + %Y-%m-%dT%H:%M:%SZ for UTC. -.. code-block:: cmake + .. versionadded:: 3.8 + If the ``SOURCE_DATE_EPOCH`` environment variable is set, + its value will be used instead of the current time. + See https://reproducible-builds.org/specs/source-date-epoch/ for details. +.. signature:: string(UUID <output_variable> NAMESPACE <namespace> NAME <name> TYPE <MD5|SHA1> [UPPER]) -.. versionadded:: 3.1 + .. versionadded:: 3.1 -Create a universally unique identifier (aka GUID) as per RFC4122 -based on the hash of the combined values of ``<namespace>`` -(which itself has to be a valid UUID) and ``<name>``. -The hash algorithm can be either ``MD5`` (Version 3 UUID) or -``SHA1`` (Version 5 UUID). -A UUID has the format ``xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`` -where each ``x`` represents a lower case hexadecimal character. -Where required, an uppercase representation can be requested -with the optional ``UPPER`` flag. + Create a universally unique identifier (aka GUID) as per RFC4122 + based on the hash of the combined values of ``<namespace>`` + (which itself has to be a valid UUID) and ``<name>``. + The hash algorithm can be either ``MD5`` (Version 3 UUID) or + ``SHA1`` (Version 5 UUID). + A UUID has the format ``xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`` + where each ``x`` represents a lower case hexadecimal character. + Where required, an uppercase representation can be requested + with the optional ``UPPER`` flag. .. _JSON: @@ -586,78 +518,72 @@ Functionality for querying a JSON string. option is not present, a fatal error message is generated. If no error occurs, the ``<error-variable>`` will be set to ``NOTFOUND``. -.. _JSON_GET: -.. code-block:: cmake - +.. signature:: string(JSON <out-var> [ERROR_VARIABLE <error-variable>] GET <json-string> <member|index> [<member|index> ...]) + :target: JSON GET -Get an element from ``<json-string>`` at the location given -by the list of ``<member|index>`` arguments. -Array and object elements will be returned as a JSON string. -Boolean elements will be returned as ``ON`` or ``OFF``. -Null elements will be returned as an empty string. -Number and string types will be returned as strings. - -.. _JSON_TYPE: -.. code-block:: cmake + Get an element from ``<json-string>`` at the location given + by the list of ``<member|index>`` arguments. + Array and object elements will be returned as a JSON string. + Boolean elements will be returned as ``ON`` or ``OFF``. + Null elements will be returned as an empty string. + Number and string types will be returned as strings. +.. signature:: string(JSON <out-var> [ERROR_VARIABLE <error-variable>] TYPE <json-string> <member|index> [<member|index> ...]) + :target: JSON TYPE -Get the type of an element in ``<json-string>`` at the location -given by the list of ``<member|index>`` arguments. The ``<out-var>`` -will be set to one of ``NULL``, ``NUMBER``, ``STRING``, ``BOOLEAN``, -``ARRAY``, or ``OBJECT``. - -.. _JSON_MEMBER: -.. code-block:: cmake + Get the type of an element in ``<json-string>`` at the location + given by the list of ``<member|index>`` arguments. The ``<out-var>`` + will be set to one of ``NULL``, ``NUMBER``, ``STRING``, ``BOOLEAN``, + ``ARRAY``, or ``OBJECT``. +.. signature:: string(JSON <out-var> [ERROR_VARIABLE <error-var>] MEMBER <json-string> [<member|index> ...] <index>) + :target: JSON MEMBER -Get the name of the ``<index>``-th member in ``<json-string>`` at the location -given by the list of ``<member|index>`` arguments. -Requires an element of object type. - -.. _JSON_LENGTH: -.. code-block:: cmake + Get the name of the ``<index>``-th member in ``<json-string>`` + at the location given by the list of ``<member|index>`` arguments. + Requires an element of object type. +.. signature:: string(JSON <out-var> [ERROR_VARIABLE <error-variable>] LENGTH <json-string> [<member|index> ...]) + :target: JSON LENGTH -Get the length of an element in ``<json-string>`` at the location -given by the list of ``<member|index>`` arguments. -Requires an element of array or object type. - -.. _JSON_REMOVE: -.. code-block:: cmake + Get the length of an element in ``<json-string>`` at the location + given by the list of ``<member|index>`` arguments. + Requires an element of array or object type. +.. signature:: string(JSON <out-var> [ERROR_VARIABLE <error-variable>] REMOVE <json-string> <member|index> [<member|index> ...]) + :target: JSON REMOVE -Remove an element from ``<json-string>`` at the location -given by the list of ``<member|index>`` arguments. The JSON string -without the removed element will be stored in ``<out-var>``. - -.. _JSON_SET: -.. code-block:: cmake + Remove an element from ``<json-string>`` at the location + given by the list of ``<member|index>`` arguments. The JSON string + without the removed element will be stored in ``<out-var>``. +.. signature:: string(JSON <out-var> [ERROR_VARIABLE <error-variable>] SET <json-string> <member|index> [<member|index> ...] <value>) + :target: JSON SET -Set an element in ``<json-string>`` at the location -given by the list of ``<member|index>`` arguments to ``<value>``. -The contents of ``<value>`` should be valid JSON. - -.. _JSON_EQUAL: -.. code-block:: cmake + Set an element in ``<json-string>`` at the location + given by the list of ``<member|index>`` arguments to ``<value>``. + The contents of ``<value>`` should be valid JSON. +.. signature:: string(JSON <out-var> [ERROR_VARIABLE <error-var>] EQUAL <json-string1> <json-string2>) + :target: JSON EQUAL -Compare the two JSON objects given by ``<json-string1>`` and ``<json-string2>`` -for equality. The contents of ``<json-string1>`` and ``<json-string2>`` -should be valid JSON. The ``<out-var>`` will be set to a true value if the -JSON objects are considered equal, or a false value otherwise. + Compare the two JSON objects given by ``<json-string1>`` + and ``<json-string2>`` for equality. The contents of ``<json-string1>`` + and ``<json-string2>`` should be valid JSON. The ``<out-var>`` + will be set to a true value if the JSON objects are considered equal, + or a false value otherwise. diff --git a/Help/command/target_compile_options.rst b/Help/command/target_compile_options.rst index 698f62d..f3ac97b 100644 --- a/Help/command/target_compile_options.rst +++ b/Help/command/target_compile_options.rst @@ -50,6 +50,10 @@ See Also * For file-specific settings, there is the source file property :prop_sf:`COMPILE_OPTIONS`. +* This command adds compile options for all languages in a target. + Use the :genex:`COMPILE_LANGUAGE` generator expression to specify + per-language compile options. + * :command:`target_compile_features` * :command:`target_link_libraries` * :command:`target_link_directories` diff --git a/Help/command/unset.rst b/Help/command/unset.rst index 1cd1398..522be89 100644 --- a/Help/command/unset.rst +++ b/Help/command/unset.rst @@ -12,19 +12,14 @@ Unset Normal Variable or Cache Entry Removes a normal variable from the current scope, causing it to become undefined. If ``CACHE`` is present, then a cache variable -is removed instead of a normal variable. Note that when evaluating -:ref:`Variable References` of the form ``${VAR}``, CMake first searches -for a normal variable with that name. If no such normal variable exists, -CMake will then search for a cache entry with that name. Because of this -unsetting a normal variable can expose a cache variable that was previously -hidden. To force a variable reference of the form ``${VAR}`` to return an -empty string, use ``set(<variable> "")``, which clears the normal variable -but leaves it defined. +is removed instead of a normal variable. If ``PARENT_SCOPE`` is present then the variable is removed from the scope above the current scope. See the same option in the :command:`set` command for further details. +.. include:: UNSET_NOTE.txt + Unset Environment Variable ^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/Help/dev/documentation.rst b/Help/dev/documentation.rst index db92022..c6fb7a6 100644 --- a/Help/dev/documentation.rst +++ b/Help/dev/documentation.rst @@ -168,46 +168,175 @@ documentation: See the `cmake-variables(7)`_ manual and the `set()`_ command. -Documentation objects in the CMake Domain come from two sources. -First, the CMake extension to Sphinx transforms every document named -with the form ``Help/<type>/<file-name>.rst`` to a domain object with -type ``<type>``. The object name is extracted from the document title, -which is expected to be of the form:: - - <object-name> - ------------- - -and to appear at or near the top of the ``.rst`` file before any other -lines starting in a letter, digit, ``<``, or ``$``. If no such title appears -literally in the ``.rst`` file, the object name is the ``<file-name>``. -If a title does appear, it is expected that ``<file-name>`` is equal -to ``<object-name>`` with any ``<`` and ``>`` characters removed, -or in the case of a ``$<genex-name>`` or ``$<genex-name:...>``, the -``genex-name``. - -Second, the CMake Domain provides directives to define objects inside -other documents: +Documentation objects in the CMake Domain come from two sources: + +1. The CMake extension to Sphinx transforms every document named + with the form ``Help/<type>/<file-name>.rst`` to a domain object with + type ``<type>``. The object name is extracted from the document title, + which is expected to be of the form:: + + <object-name> + ------------- + + and to appear at or near the top of the ``.rst`` file before any other lines + starting in a letter, digit, ``<``, or ``$``. If no such title appears + literally in the ``.rst`` file, the object name is the ``<file-name>``. + If a title does appear, it is expected that ``<file-name>`` is equal + to ``<object-name>`` with any ``<`` and ``>`` characters removed, + or in the case of a ``$<genex-name>`` or ``$<genex-name:...>``, the + ``genex-name``. + +2. `CMake Domain directives`_ may be used in documents to explicitly define + some object types: + + * `command directive`_ + * `envvar directive`_ + * `genex directive`_ + * `variable directive`_ + + Object types for which no directive is available must be defined using + the document transform above. + +CMake Domain Directives +----------------------- + +The CMake Domain provides the following directives. + +``command`` directive +^^^^^^^^^^^^^^^^^^^^^ + +Document a "command" object: + +.. code-block:: rst + + .. command:: <command-name> + + This indented block documents <command-name>. + +The directive requires a single argument, the command name. + +``envvar`` directive +^^^^^^^^^^^^^^^^^^^^ + +Document an "envvar" object: .. code-block:: rst - .. command:: <command-name> + .. envvar:: <envvar-name> + + This indented block documents <envvar-name>. + +The directive requires a single argument, the environment variable name. - This indented block documents <command-name>. +``genex`` directive +^^^^^^^^^^^^^^^^^^^ - .. envvar:: <envvar-name> +Document a "genex" object: - This indented block documents <envvar-name>. +.. code-block:: rst .. genex:: <genex-name> This indented block documents <genex-name>. +The directive requires a single argument, the generator expression name. + +The optional ``:target:`` option allows a custom target name to be specified. +Because this will affect the ability to reference the "genex" object using the +``:genex:`` role, this option should be used very sparingly. + +``signature`` directive +^^^^^^^^^^^^^^^^^^^^^^^ + +Document `CMake Command Signatures <Style: CMake Command Signatures_>`_ +within a ``Help/command/<command-name>.rst`` document. + +.. code-block:: rst + + .. signature:: <command-name>(<signature>) + + This indented block documents one or more signatures of a CMake command. + +The ``signature`` directive requires one argument, the signature summary: + +* One or more signatures must immediately follow the ``::``. + The first signature may optionally be placed on the same line. + A blank line following the ``signature`` directive will result in a + documentation generation error: ``1 argument(s) required, 0 supplied``. + +* Signatures may be split across multiple lines, but the final ``)`` of each + signature must be the last character on its line. + +* Blank lines between signatures are not allowed. (Content after a blank line + is treated as part of the description.) + +* Whitespace in signatures is not preserved. To document a complex signature, + abbreviate it in the ``signature`` directive argument and specify the full + signature in a ``code-block`` in the description. + +The ``signature`` directive generates a hyperlink target for each signature: + +* Default target names are automatically extracted from leading "keyword" + arguments in the signatures, where a keyword is any sequence of + non-space starting with a letter. For example, the signature + ``string(REGEX REPLACE <match-regex> ...)`` generates the target + ``REGEX REPLACE``, similar to ``.. _`REGEX REPLACE`:``. + +* Custom target names may be specified using a ``:target:`` option. + For example: + + .. code-block:: rst + + .. signature:: + cmake_path(GET <path-var> ROOT_NAME <out-var>) + cmake_path(GET <path-var> ROOT_PATH <out-var>) + :target: + GET ROOT_NAME + GET ROOT_PATH + + Provide a custom target name for each signature, one per line. + The first target may optionally be placed on the same line as ``:target:``. + +* If a target name is already in use earlier in the document, no hyperlink + target will be generated. + +* The targets may be referenced from within the same document using + ```REF`_`` or ```TEXT <REF_>`_`` syntax. Like reStructuredText section + headers, the targets do not work with Sphinx ``:ref:`` syntax, however + they can be globally referenced using e.g. ``:command:`string(APPEND)```. + +Although whitespace in the signature is not preserved, by default, line breaks +are suppressed inside of square- or angle-brackets. This behavior can be +controlled using the ``:break:`` option; note, however, that there is no way +to *force* a line break. The default value is 'smart'. Allowable values are: + + ``all`` + Allow line breaks at any whitespace. + + ``smart`` (default) + Allow line breaks at whitespace, except between matched square- or + angle-brackets. For example, if a signature contains the text + ``<input>... [OUTPUT_VARIABLE <out-var>]``, a line break would be allowed + after ``<input>...`` but not between ``OUTPUT_VARIABLE`` and ``<out-var>``. + + ``verbatim`` + Allow line breaks only where the source document contains a newline. + +The directive treats its content as the documentation of the signature(s). +Indent the signature documentation accordingly. + +``variable`` directive +^^^^^^^^^^^^^^^^^^^^^^ + +Document a "variable" object: + +.. code-block:: rst + .. variable:: <variable-name> This indented block documents <variable-name>. -Object types for which no directive is available must be defined using -the first approach above. +The directive requires a single argument, the variable name. .. _`Sphinx Domain`: http://sphinx-doc.org/domains.html .. _`cmake(1)`: https://cmake.org/cmake/help/latest/manual/cmake.1.html @@ -266,6 +395,10 @@ object names like ``OUTPUT_NAME_<CONFIG>``. The form ``a <b>``, with a space preceding ``<``, is still interpreted as a link text with an explicit target. +Additionally, the ``cref`` role may be used to create references +to local targets that have literal styling. This is especially +useful for referencing a subcommand in the command's documentation. + .. _`list()`: https://cmake.org/cmake/help/latest/command/list.html .. _`list(APPEND)`: https://cmake.org/cmake/help/latest/command/list.html .. _`list(APPEND) sub-command`: https://cmake.org/cmake/help/latest/command/list.html @@ -329,11 +462,11 @@ paragraph. Style: CMake Command Signatures ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Command signatures should be marked up as plain literal blocks, not as -cmake ``code-blocks``. - -Signatures are separated from preceding content by a section header. -That is, use: +A ``Help/command/<command-name>.rst`` document defines one ``command`` +object in the `CMake Domain`_, but some commands have multiple signatures. +Use the CMake Domain's `signature directive`_ to document each signature. +Separate signatures from preceding content by a section header. +For example: .. code-block:: rst @@ -342,17 +475,23 @@ That is, use: Normal Libraries ^^^^^^^^^^^^^^^^ - :: - + .. signature:: add_library(<lib> ...) - This signature is used for ... + This signature is used for ... + +Use the following conventions in command signature documentation: + +* Use an angle-bracket ``<placeholder>`` for arguments to be specified + by the caller. Refer to them in prose using + `inline literal <Style: Inline Literals_>`_ syntax. + +* Wrap optional parts with square brackets. + +* Mark repeatable parts with a trailing ellipsis (``...``). -Signatures of commands should wrap optional parts with square brackets, -and should mark list of optional arguments with an ellipsis (``...``). -Elements of the signature which are specified by the user should be -specified with angle brackets, and may be referred to in prose using -``inline-literal`` syntax. +The ``signature`` directive may be used multiple times for different +signatures of the same command. Style: Boolean Constants ^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/Help/envvar/CMAKE_MAXIMUM_RECURSION_DEPTH.rst b/Help/envvar/CMAKE_MAXIMUM_RECURSION_DEPTH.rst new file mode 100644 index 0000000..2d65b60 --- /dev/null +++ b/Help/envvar/CMAKE_MAXIMUM_RECURSION_DEPTH.rst @@ -0,0 +1,10 @@ +CMAKE_MAXIMUM_RECURSION_DEPTH +----------------------------- + +.. versionadded:: 3.27 + +.. include:: ENV_VAR.txt + +Maximum recursion depth for CMake scripts. This environment variable is +used if the :variable:`CMAKE_MAXIMUM_RECURSION_DEPTH` variable is not set. +See that variable's documentation for details. diff --git a/Help/guide/tutorial/Adding Generator Expressions.rst b/Help/guide/tutorial/Adding Generator Expressions.rst index 08f3eea..aba9f7a 100644 --- a/Help/guide/tutorial/Adding Generator Expressions.rst +++ b/Help/guide/tutorial/Adding Generator Expressions.rst @@ -105,7 +105,7 @@ The specific lines to remove are as follows: :name: CMakeLists.txt-CXX_STANDARD-variable-remove :language: cmake :start-after: # specify the C++ standard - :end-before: # TODO 5: Create helper variables + :end-before: # TODO 6: Create helper variables Next, we need to create an interface library, ``tutorial_compiler_flags``. And then use :command:`target_compile_features` to add the compiler feature @@ -128,7 +128,8 @@ then use :command:`target_compile_features` to add the compiler feature </details> Finally, with our interface library set up, we need to link our -executable ``Target`` and our ``MathFunctions`` library to our new +executable ``Target``, our ``MathFunctions`` library, and our ``SqrtLibrary`` +library to our new ``tutorial_compiler_flags`` library. Respectively, the code will look like this: @@ -147,7 +148,7 @@ this: </details> -and this: +this: .. raw:: html @@ -158,12 +159,30 @@ and this: :name: MathFunctions-CMakeLists.txt-target_link_libraries-step4 :language: cmake :start-after: # link our compiler flags interface library - :end-before: # TODO 1 + :end-before: target_link_libraries(MathFunctions + +.. raw:: html + + </details> + +and this: + +.. raw:: html + + <details><summary>TODO 4: Click to show/hide answer</summary> + +.. literalinclude:: Step5/MathFunctions/CMakeLists.txt + :caption: TODO 4: MathFunctions/CMakeLists.txt + :name: MathFunctions-SqrtLibrary-target_link_libraries-step4 + :language: cmake + :start-after: target_link_libraries(SqrtLibrary + :end-before: endif() .. raw:: html </details> + With this, all of our code still requires C++ 11 to build. Notice though that with this method, it gives us the ability to be specific about which targets get specific requirements. In addition, we create a single @@ -199,8 +218,8 @@ Files to Edit Getting Started --------------- -Start with the resulting files from Exercise 1. Complete ``TODO 4`` through -``TODO 7``. +Start with the resulting files from Exercise 1. Complete ``TODO 5`` through +``TODO 8``. First, in the top level ``CMakeLists.txt`` file, we need to set the :command:`cmake_minimum_required` to ``3.15``. In this exercise we are going @@ -230,10 +249,10 @@ version ``3.15``: .. raw:: html - <details><summary>TODO 4: Click to show/hide answer</summary> + <details><summary>TODO 5: Click to show/hide answer</summary> .. literalinclude:: Step5/CMakeLists.txt - :caption: TODO 4: CMakeLists.txt + :caption: TODO 5: CMakeLists.txt :name: MathFunctions-CMakeLists.txt-minimum-required-step4 :language: cmake :end-before: # set the project name and version @@ -249,10 +268,10 @@ variables ``gcc_like_cxx`` and ``msvc_cxx`` as follows: .. raw:: html - <details><summary>TODO 5: Click to show/hide answer</summary> + <details><summary>TODO 6: Click to show/hide answer</summary> .. literalinclude:: Step5/CMakeLists.txt - :caption: TODO 5: CMakeLists.txt + :caption: TODO 6: CMakeLists.txt :name: CMakeLists.txt-compile_lang_and_id :language: cmake :start-after: # the BUILD_INTERFACE genex @@ -270,10 +289,10 @@ interface library. .. raw:: html - <details><summary>TODO 6: Click to show/hide answer</summary> + <details><summary>TODO 7: Click to show/hide answer</summary> .. code-block:: cmake - :caption: TODO 6: CMakeLists.txt + :caption: TODO 7: CMakeLists.txt :name: CMakeLists.txt-compile_flags target_compile_options(tutorial_compiler_flags INTERFACE @@ -292,10 +311,10 @@ condition. The resulting full code looks like the following: .. raw:: html - <details><summary>TODO 7: Click to show/hide answer</summary> + <details><summary>TODO 8: Click to show/hide answer</summary> .. literalinclude:: Step5/CMakeLists.txt - :caption: TODO 7: CMakeLists.txt + :caption: TODO 8: CMakeLists.txt :name: CMakeLists.txt-target_compile_options-genex :language: cmake :start-after: set(msvc_cxx "$<COMPILE_LANG_AND_ID:CXX,MSVC>") diff --git a/Help/guide/tutorial/Adding a Custom Command and Generated File.rst b/Help/guide/tutorial/Adding a Custom Command and Generated File.rst index 9e6311e..c71a889 100644 --- a/Help/guide/tutorial/Adding a Custom Command and Generated File.rst +++ b/Help/guide/tutorial/Adding a Custom Command and Generated File.rst @@ -18,17 +18,16 @@ In the ``MathFunctions`` subdirectory, a new source file named After reviewing the file, we can see that the table is produced as valid C++ code and that the output filename is passed in as an argument. -The next step is to add the appropriate commands to the -``MathFunctions/CMakeLists.txt`` file to build the MakeTable executable and +The next step is to create ``MathFunctions/MakeTable.cmake``. Then, add the +appropriate commands to the file to build the ``MakeTable`` executable and then run it as part of the build process. A few commands are needed to accomplish this. -First, in the ``USE_MYMATH`` section of ``MathFunctions/CMakeLists.txt``, -we add an executable for ``MakeTable``. +First, we add an executable for ``MakeTable``. -.. literalinclude:: Step9/MathFunctions/CMakeLists.txt - :caption: MathFunctions/CMakeLists.txt - :name: MathFunctions/CMakeLists.txt-add_executable-MakeTable +.. literalinclude:: Step9/MathFunctions/MakeTable.cmake + :caption: MathFunctions/MakeTable.cmake + :name: MathFunctions/MakeTable.cmake-add_executable-MakeTable :language: cmake :start-after: # first we add the executable that generates the table :end-before: target_link_libraries @@ -36,9 +35,9 @@ we add an executable for ``MakeTable``. After creating the executable, we add the ``tutorial_compiler_flags`` to our executable using :command:`target_link_libraries`. -.. literalinclude:: Step9/MathFunctions/CMakeLists.txt - :caption: MathFunctions/CMakeLists.txt - :name: MathFunctions/CMakeLists.txt-link-tutorial-compiler-flags +.. literalinclude:: Step9/MathFunctions/MakeTable.cmake + :caption: MathFunctions/MakeTable.cmake + :name: MathFunctions/MakeTable.cmake-link-tutorial-compiler-flags :language: cmake :start-after: add_executable :end-before: # add the command to generate @@ -46,16 +45,15 @@ executable using :command:`target_link_libraries`. Then we add a custom command that specifies how to produce ``Table.h`` by running MakeTable. -.. literalinclude:: Step9/MathFunctions/CMakeLists.txt - :caption: MathFunctions/CMakeLists.txt - :name: MathFunctions/CMakeLists.txt-add_custom_command-Table.h +.. literalinclude:: Step9/MathFunctions/MakeTable.cmake + :caption: MathFunctions/MakeTable.cmake + :name: MathFunctions/MakeTable.cmake-add_custom_command-Table.h :language: cmake :start-after: # add the command to generate the source code - :end-before: # library that just does sqrt Next we have to let CMake know that ``mysqrt.cxx`` depends on the generated file ``Table.h``. This is done by adding the generated ``Table.h`` to the list -of sources for the library MathFunctions. +of sources for the library ``SqrtLibrary``. .. literalinclude:: Step9/MathFunctions/CMakeLists.txt :caption: MathFunctions/CMakeLists.txt @@ -74,17 +72,15 @@ directories so that ``Table.h`` can be found and included by ``mysqrt.cxx``. :start-after: # state that we depend on our bin :end-before: target_link_libraries -As the last thing in our ``USE_MYMATH`` section, we need to link the our -flags onto ``SqrtLibrary`` and then link ``SqrtLibrary`` onto -``MathFunctions``. This makes the resulting ``USE_MYMATH`` section look like -the following: +As the last step, we need to include +``MakeTable.cmake`` at the top of the ``MathFunctions/CMakeLists.txt``. .. literalinclude:: Step9/MathFunctions/CMakeLists.txt :caption: MathFunctions/CMakeLists.txt - :name: MathFunctions/CMakeLists.txt-full_USE_MYMATH-section + :name: MathFunctions/CMakeLists.txt-include-MakeTable.cmake :language: cmake - :start-after: if (USE_MYMATH) - :end-before: endif() + :start-after: # generate Table.h + :end-before: # library that just does sqrt Now let's use the generated table. First, modify ``mysqrt.cxx`` to include ``Table.h``. Next, we can rewrite the ``mysqrt`` function to use the table: diff --git a/Help/guide/tutorial/Adding a Library.rst b/Help/guide/tutorial/Adding a Library.rst index 2dd731f..d606f30 100644 --- a/Help/guide/tutorial/Adding a Library.rst +++ b/Help/guide/tutorial/Adding a Library.rst @@ -100,11 +100,11 @@ source files for the library are passed as an argument to <details><summary>TODO 1: Click to show/hide answer</summary> -.. literalinclude:: Step3/MathFunctions/CMakeLists.txt +.. code-block:: cmake :caption: TODO 1: MathFunctions/CMakeLists.txt :name: MathFunctions/CMakeLists.txt-add_library - :language: cmake - :end-before: # TODO 1 + + add_library(MathFunctions MathFunctions.cxx mysqrt.cxx) .. raw:: html @@ -191,7 +191,7 @@ Lastly, replace ``sqrt`` with our library function ``mathfunctions::mysqrt``. <details><summary>TODO 6: Click to show/hide answer</summary> .. literalinclude:: Step3/tutorial.cxx - :caption: TODO 7: tutorial.cxx + :caption: TODO 6: tutorial.cxx :name: CMakeLists.txt-option :language: cmake :start-after: const double inputValue = std::stod(argv[1]); @@ -238,7 +238,7 @@ Getting Started --------------- Start with the resulting files from Exercise 1. Complete ``TODO 7`` through -``TODO 9``. +``TODO 14``. First create a variable ``USE_MYMATH`` using the :command:`option` command in ``MathFunctions/CMakeLists.txt``. In that same file, use that option @@ -247,6 +247,10 @@ to pass a compile definition to the ``MathFunctions`` library. Then, update ``MathFunctions.cxx`` to redirect compilation based on ``USE_MYMATH``. +Lastly, prevent ``mysqrt.cxx`` from being compiled when ``USE_MYMATH`` is on +by making it its own library inside of the ``USE_MYMATH`` block of +``MathFunctions/CMakeLists.txt``. + Build and Run ------------- @@ -315,16 +319,22 @@ definition ``USE_MYMATH``. <details><summary>TODO 8: Click to show/hide answer</summary> -.. literalinclude:: Step3/MathFunctions/CMakeLists.txt +.. code-block:: cmake :caption: TODO 8: MathFunctions/CMakeLists.txt :name: CMakeLists.txt-USE_MYMATH - :language: cmake - :start-after: USE_MYMATH "Use tutorial provided math implementation" ON) + + if (USE_MYMATH) + target_compile_definitions(MathFunctions PRIVATE "USE_MYMATH") + endif() .. raw:: html </details> +When ``USE_MYMATH`` is ``ON``, the compile definition ``USE_MYMATH`` will +be set. We can then use this compile definition to enable or disable +sections of our source code. + The corresponding changes to the source code are fairly straightforward. In ``MathFunctions.cxx``, we make ``USE_MYMATH`` control which square root function is used: @@ -377,10 +387,68 @@ Finally, we need to include ``cmath`` now that we are using ``std::sqrt``. </details> -When ``USE_MYMATH`` is ``ON``, the compile definition ``USE_MYMATH`` will -be set. We can then use this compile definition to enable or disable -sections of our source code. With this strategy, we allow users to -toggle ``USE_MYMATH`` to manipulate what library is used in the build. +At this point, if ``USE_MYMATH`` is ``OFF``, ``mysqrt.cxx`` would not be used +but it will still be compiled because the ``MathFunctions`` target has +``mysqrt.cxx`` listed under sources. + +There are a few ways to fix this. The first option is to use +:command:`target_sources` to add ``mysqrt.cxx`` from within the ``USE_MYMATH`` +block. Another option is to create an additional library within the +``USE_MYMATH`` block which is responsible for compiling ``mysqrt.cxx``. For +the sake of this tutorial, we are going to create an additional library. + +First, from within ``USE_MYMATH`` create a library called ``SqrtLibrary`` +that has sources ``mysqrt.cxx``. + +.. raw:: html + + <details><summary>TODO 12: Click to show/hide answer</summary> + +.. literalinclude:: Step3/MathFunctions/CMakeLists.txt + :caption: TODO 12 : MathFunctions/CMakeLists.txt + :name: MathFunctions/CMakeLists.txt-add_library-SqrtLibrary + :language: cmake + :start-after: # library that just does sqrt + :end-before: target_link_libraries(MathFunctions + +.. raw:: html + + </details> + +Next, we link ``SqrtLibrary`` onto ``MathFunctions`` when ``USE_MYMATH`` is +enabled. + +.. raw:: html + + <details><summary>TODO 13: Click to show/hide answer</summary> + +.. literalinclude:: Step3/MathFunctions/CMakeLists.txt + :caption: TODO 13 : MathFunctions/CMakeLists.txt + :name: MathFunctions/CMakeLists.txt-target_link_libraries-SqrtLibrary + :language: cmake + :lines: 16-18 + +.. raw:: html + + </details> + +Finally, we can remove ``mysqrt.cxx`` from our ``MathFunctions`` library +source list because it will be pulled in when ``SqrtLibrary`` is included. + +.. raw:: html + + <details><summary>TODO 14: Click to show/hide answer</summary> + +.. literalinclude:: Step3/MathFunctions/CMakeLists.txt + :caption: TODO 14 : MathFunctions/CMakeLists.txt + :name: MathFunctions/CMakeLists.txt-remove-mysqrt.cxx-MathFunctions + :language: cmake + :end-before: # TODO 1: + +.. raw:: html + + </details> With these changes, the ``mysqrt`` function is now completely optional to -whoever is building and using the ``MathFunctions`` library. +whoever is building and using the ``MathFunctions`` library. Users can toggle +``USE_MYMATH`` to manipulate what library is used in the build. diff --git a/Help/guide/tutorial/Complete/MathFunctions/CMakeLists.txt b/Help/guide/tutorial/Complete/MathFunctions/CMakeLists.txt index d256db2..b221506 100644 --- a/Help/guide/tutorial/Complete/MathFunctions/CMakeLists.txt +++ b/Help/guide/tutorial/Complete/MathFunctions/CMakeLists.txt @@ -15,16 +15,7 @@ if(USE_MYMATH) target_compile_definitions(MathFunctions PRIVATE "USE_MYMATH") - # first we add the executable that generates the table - add_executable(MakeTable MakeTable.cxx) - target_link_libraries(MakeTable PRIVATE tutorial_compiler_flags) - - # add the command to generate the source code - add_custom_command( - OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/Table.h - COMMAND MakeTable ${CMAKE_CURRENT_BINARY_DIR}/Table.h - DEPENDS MakeTable - ) + include(MakeTable.cmake) # generates Table.h # library that just does sqrt add_library(SqrtLibrary STATIC diff --git a/Help/guide/tutorial/Complete/MathFunctions/MakeTable.cmake b/Help/guide/tutorial/Complete/MathFunctions/MakeTable.cmake new file mode 100644 index 0000000..12865a9 --- /dev/null +++ b/Help/guide/tutorial/Complete/MathFunctions/MakeTable.cmake @@ -0,0 +1,10 @@ +# first we add the executable that generates the table +add_executable(MakeTable MakeTable.cxx) +target_link_libraries(MakeTable PRIVATE tutorial_compiler_flags) + +# add the command to generate the source code +add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/Table.h + COMMAND MakeTable ${CMAKE_CURRENT_BINARY_DIR}/Table.h + DEPENDS MakeTable + ) diff --git a/Help/guide/tutorial/Step10/MathFunctions/CMakeLists.txt b/Help/guide/tutorial/Step10/MathFunctions/CMakeLists.txt index 6f6c430..36b3fe1 100644 --- a/Help/guide/tutorial/Step10/MathFunctions/CMakeLists.txt +++ b/Help/guide/tutorial/Step10/MathFunctions/CMakeLists.txt @@ -13,16 +13,7 @@ if(USE_MYMATH) target_compile_definitions(MathFunctions PRIVATE "USE_MYMATH") - # first we add the executable that generates the table - add_executable(MakeTable MakeTable.cxx) - target_link_libraries(MakeTable PRIVATE tutorial_compiler_flags) - - # add the command to generate the source code - add_custom_command( - OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/Table.h - COMMAND MakeTable ${CMAKE_CURRENT_BINARY_DIR}/Table.h - DEPENDS MakeTable - ) + include(MakeTable.cmake) # generates Table.h # library that just does sqrt add_library(SqrtLibrary STATIC diff --git a/Help/guide/tutorial/Step10/MathFunctions/MakeTable.cmake b/Help/guide/tutorial/Step10/MathFunctions/MakeTable.cmake new file mode 100644 index 0000000..12865a9 --- /dev/null +++ b/Help/guide/tutorial/Step10/MathFunctions/MakeTable.cmake @@ -0,0 +1,10 @@ +# first we add the executable that generates the table +add_executable(MakeTable MakeTable.cxx) +target_link_libraries(MakeTable PRIVATE tutorial_compiler_flags) + +# add the command to generate the source code +add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/Table.h + COMMAND MakeTable ${CMAKE_CURRENT_BINARY_DIR}/Table.h + DEPENDS MakeTable + ) diff --git a/Help/guide/tutorial/Step11/MathFunctions/CMakeLists.txt b/Help/guide/tutorial/Step11/MathFunctions/CMakeLists.txt index a60fb63..813bf90 100644 --- a/Help/guide/tutorial/Step11/MathFunctions/CMakeLists.txt +++ b/Help/guide/tutorial/Step11/MathFunctions/CMakeLists.txt @@ -13,16 +13,7 @@ if(USE_MYMATH) target_compile_definitions(MathFunctions PRIVATE "USE_MYMATH") - # first we add the executable that generates the table - add_executable(MakeTable MakeTable.cxx) - target_link_libraries(MakeTable PRIVATE tutorial_compiler_flags) - - # add the command to generate the source code - add_custom_command( - OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/Table.h - COMMAND MakeTable ${CMAKE_CURRENT_BINARY_DIR}/Table.h - DEPENDS MakeTable - ) + include(MakeTable.cmake) # generates Table.h # library that just does sqrt add_library(SqrtLibrary STATIC diff --git a/Help/guide/tutorial/Step11/MathFunctions/MakeTable.cmake b/Help/guide/tutorial/Step11/MathFunctions/MakeTable.cmake new file mode 100644 index 0000000..12865a9 --- /dev/null +++ b/Help/guide/tutorial/Step11/MathFunctions/MakeTable.cmake @@ -0,0 +1,10 @@ +# first we add the executable that generates the table +add_executable(MakeTable MakeTable.cxx) +target_link_libraries(MakeTable PRIVATE tutorial_compiler_flags) + +# add the command to generate the source code +add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/Table.h + COMMAND MakeTable ${CMAKE_CURRENT_BINARY_DIR}/Table.h + DEPENDS MakeTable + ) diff --git a/Help/guide/tutorial/Step12/MathFunctions/CMakeLists.txt b/Help/guide/tutorial/Step12/MathFunctions/CMakeLists.txt index a85f3cb..38694dd 100644 --- a/Help/guide/tutorial/Step12/MathFunctions/CMakeLists.txt +++ b/Help/guide/tutorial/Step12/MathFunctions/CMakeLists.txt @@ -15,16 +15,7 @@ if(USE_MYMATH) target_compile_definitions(MathFunctions PRIVATE "USE_MYMATH") - # first we add the executable that generates the table - add_executable(MakeTable MakeTable.cxx) - target_link_libraries(MakeTable PRIVATE tutorial_compiler_flags) - - # add the command to generate the source code - add_custom_command( - OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/Table.h - COMMAND MakeTable ${CMAKE_CURRENT_BINARY_DIR}/Table.h - DEPENDS MakeTable - ) + include(MakeTable.cmake) # generates Table.h # library that just does sqrt add_library(SqrtLibrary STATIC diff --git a/Help/guide/tutorial/Step12/MathFunctions/MakeTable.cmake b/Help/guide/tutorial/Step12/MathFunctions/MakeTable.cmake new file mode 100644 index 0000000..12865a9 --- /dev/null +++ b/Help/guide/tutorial/Step12/MathFunctions/MakeTable.cmake @@ -0,0 +1,10 @@ +# first we add the executable that generates the table +add_executable(MakeTable MakeTable.cxx) +target_link_libraries(MakeTable PRIVATE tutorial_compiler_flags) + +# add the command to generate the source code +add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/Table.h + COMMAND MakeTable ${CMAKE_CURRENT_BINARY_DIR}/Table.h + DEPENDS MakeTable + ) diff --git a/Help/guide/tutorial/Step2/MathFunctions/CMakeLists.txt b/Help/guide/tutorial/Step2/MathFunctions/CMakeLists.txt index c468b0e..c3cd806 100644 --- a/Help/guide/tutorial/Step2/MathFunctions/CMakeLists.txt +++ b/Help/guide/tutorial/Step2/MathFunctions/CMakeLists.txt @@ -1,7 +1,15 @@ -# TODO 1: Add a library called MathFunctions +# TODO 14: Remove mysqrt.cxx from the list of sources + +# TODO 1: Add a library called MathFunctions with sources MathFunctions.cxx +# and mysqrt.cxx # Hint: You will need the add_library command # TODO 7: Create a variable USE_MYMATH using option and set default to ON # TODO 8: If USE_MYMATH is ON, use target_compile_definitions to pass # USE_MYMATH as a precompiled definition to our source files + +# TODO 12: When USE_MYMATH is ON, add a library for SqrtLibrary with +# source mysqrt.cxx + +# TODO 13: When USE_MYMATH is ON, link SqrtLibrary to the MathFunctions Library diff --git a/Help/guide/tutorial/Step3/MathFunctions/CMakeLists.txt b/Help/guide/tutorial/Step3/MathFunctions/CMakeLists.txt index 90d6c24..6f86ffe 100644 --- a/Help/guide/tutorial/Step3/MathFunctions/CMakeLists.txt +++ b/Help/guide/tutorial/Step3/MathFunctions/CMakeLists.txt @@ -1,4 +1,4 @@ -add_library(MathFunctions MathFunctions.cxx mysqrt.cxx) +add_library(MathFunctions MathFunctions.cxx) # TODO 1: State that anybody linking to MathFunctions needs to include the # current source directory, while MathFunctions itself doesn't. @@ -8,4 +8,11 @@ add_library(MathFunctions MathFunctions.cxx mysqrt.cxx) option(USE_MYMATH "Use tutorial provided math implementation" ON) if (USE_MYMATH) target_compile_definitions(MathFunctions PRIVATE "USE_MYMATH") + + # library that just does sqrt + add_library(SqrtLibrary STATIC + mysqrt.cxx + ) + + target_link_libraries(MathFunctions PUBLIC SqrtLibrary) endif() diff --git a/Help/guide/tutorial/Step4/CMakeLists.txt b/Help/guide/tutorial/Step4/CMakeLists.txt index dcda135..7531fb4 100644 --- a/Help/guide/tutorial/Step4/CMakeLists.txt +++ b/Help/guide/tutorial/Step4/CMakeLists.txt @@ -1,4 +1,4 @@ -# TODO 4: Update the minimum required version to 3.15 +# TODO 5: Update the minimum required version to 3.15 cmake_minimum_required(VERSION 3.10) @@ -15,19 +15,19 @@ project(Tutorial VERSION 1.0) set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED True) -# TODO 5: Create helper variables to determine which compiler we are using: +# TODO 6: Create helper variables to determine which compiler we are using: # * Create a new variable gcc_like_cxx that is true if we are using CXX and # any of the following compilers: ARMClang, AppleClang, Clang, GNU, LCC # * Create a new variable msvc_cxx that is true if we are using CXX and MSVC # Hint: Use set() and COMPILE_LANG_AND_ID -# TODO 6: Add warning flag compile options to the interface library +# TODO 7: Add warning flag compile options to the interface library # tutorial_compiler_flags. # * For gcc_like_cxx, add flags -Wall;-Wextra;-Wshadow;-Wformat=2;-Wunused # * For msvc_cxx, add flags -W3 # Hint: Use target_compile_options() -# TODO 7: With nested generator expressions, only use the flags for the +# TODO 8: With nested generator expressions, only use the flags for the # build-tree # Hint: Use BUILD_INTERFACE diff --git a/Help/guide/tutorial/Step4/MathFunctions/CMakeLists.txt b/Help/guide/tutorial/Step4/MathFunctions/CMakeLists.txt index cc71d86..ffab4f0 100644 --- a/Help/guide/tutorial/Step4/MathFunctions/CMakeLists.txt +++ b/Help/guide/tutorial/Step4/MathFunctions/CMakeLists.txt @@ -1,4 +1,5 @@ -add_library(MathFunctions MathFunctions.cxx mysqrt.cxx) +# create the MathFunctions library +add_library(MathFunctions MathFunctions.cxx) # state that anybody linking to us needs to include the current source dir # to find MathFunctions.h, while we don't. @@ -10,6 +11,15 @@ target_include_directories(MathFunctions option(USE_MYMATH "Use tutorial provided math implementation" ON) if (USE_MYMATH) target_compile_definitions(MathFunctions PRIVATE "USE_MYMATH") + + # library that just does sqrt + add_library(SqrtLibrary STATIC + mysqrt.cxx + ) + + # TODO 4: Link to tutorial_compiler_flags + + target_link_libraries(MathFunctions PUBLIC SqrtLibrary) endif() # TODO 3: Link to tutorial_compiler_flags diff --git a/Help/guide/tutorial/Step5/MathFunctions/CMakeLists.txt b/Help/guide/tutorial/Step5/MathFunctions/CMakeLists.txt index 000a786..0c688f2 100644 --- a/Help/guide/tutorial/Step5/MathFunctions/CMakeLists.txt +++ b/Help/guide/tutorial/Step5/MathFunctions/CMakeLists.txt @@ -1,4 +1,4 @@ -add_library(MathFunctions MathFunctions.cxx mysqrt.cxx) +add_library(MathFunctions MathFunctions.cxx) # state that anybody linking to us needs to include the current source dir # to find MathFunctions.h, while we don't. @@ -10,6 +10,15 @@ target_include_directories(MathFunctions option(USE_MYMATH "Use tutorial provided math implementation" ON) if (USE_MYMATH) target_compile_definitions(MathFunctions PRIVATE "USE_MYMATH") + + # library that just does sqrt + add_library(SqrtLibrary STATIC + mysqrt.cxx + ) + + # link our compiler flags interface library + target_link_libraries(SqrtLibrary PUBLIC tutorial_compiler_flags) + target_link_libraries(MathFunctions PRIVATE SqrtLibrary) endif() # link our compiler flags interface library diff --git a/Help/guide/tutorial/Step6/MathFunctions/CMakeLists.txt b/Help/guide/tutorial/Step6/MathFunctions/CMakeLists.txt index 623cb74..b1b925e 100644 --- a/Help/guide/tutorial/Step6/MathFunctions/CMakeLists.txt +++ b/Help/guide/tutorial/Step6/MathFunctions/CMakeLists.txt @@ -1,4 +1,4 @@ -add_library(MathFunctions MathFunctions.cxx mysqrt.cxx) +add_library(MathFunctions MathFunctions.cxx) # state that anybody linking to us needs to include the current source dir # to find MathFunctions.h, while we don't. @@ -10,6 +10,14 @@ target_include_directories(MathFunctions option(USE_MYMATH "Use tutorial provided math implementation" ON) if (USE_MYMATH) target_compile_definitions(MathFunctions PRIVATE "USE_MYMATH") + + # library that just does sqrt + add_library(SqrtLibrary STATIC + mysqrt.cxx + ) + + target_link_libraries(SqrtLibrary PUBLIC tutorial_compiler_flags) + target_link_libraries(MathFunctions PRIVATE SqrtLibrary) endif() # link our compiler flags interface library @@ -17,6 +25,9 @@ target_link_libraries(MathFunctions PUBLIC tutorial_compiler_flags) # install libs set(installable_libs MathFunctions tutorial_compiler_flags) +if(TARGET SqrtLibrary) + list(APPEND installable_libs SqrtLibrary) +endif() install(TARGETS ${installable_libs} DESTINATION lib) # install include headers install(FILES MathFunctions.h DESTINATION include) diff --git a/Help/guide/tutorial/Step7/MathFunctions/CMakeLists.txt b/Help/guide/tutorial/Step7/MathFunctions/CMakeLists.txt index c0d1e72..897ec0e 100644 --- a/Help/guide/tutorial/Step7/MathFunctions/CMakeLists.txt +++ b/Help/guide/tutorial/Step7/MathFunctions/CMakeLists.txt @@ -1,4 +1,4 @@ -add_library(MathFunctions MathFunctions.cxx mysqrt.cxx) +add_library(MathFunctions MathFunctions.cxx) # state that anybody linking to us needs to include the current source dir # to find MathFunctions.h, while we don't. @@ -11,6 +11,13 @@ option(USE_MYMATH "Use tutorial provided math implementation" ON) if (USE_MYMATH) target_compile_definitions(MathFunctions PRIVATE "USE_MYMATH") + # library that just does sqrt + add_library(SqrtLibrary STATIC + mysqrt.cxx + ) + + target_link_libraries(SqrtLibrary PUBLIC tutorial_compiler_flags) + # TODO 1: Include CheckCXXSourceCompiles # TODO 2: Use check_cxx_source_compiles with simple C++ code to verify @@ -27,9 +34,11 @@ if (USE_MYMATH) # } # TODO 3: Conditionally on HAVE_LOG and HAVE_EXP, add private compile - # definitions "HAVE_LOG" and "HAVE_EXP" to the MathFunctions target. + # definitions "HAVE_LOG" and "HAVE_EXP" to the SqrtLibrary target. # Hint: Use target_compile_definitions() + + target_link_libraries(MathFunctions PRIVATE SqrtLibrary) endif() # link our compiler flags interface library @@ -37,6 +46,9 @@ target_link_libraries(MathFunctions PUBLIC tutorial_compiler_flags) # install libs set(installable_libs MathFunctions tutorial_compiler_flags) +if(TARGET SqrtLibrary) + list(APPEND installable_libs SqrtLibrary) +endif() install(TARGETS ${installable_libs} DESTINATION lib) # install include headers install(FILES MathFunctions.h DESTINATION include) diff --git a/Help/guide/tutorial/Step8/MathFunctions/CMakeLists.txt b/Help/guide/tutorial/Step8/MathFunctions/CMakeLists.txt index 861014d..872a24a 100644 --- a/Help/guide/tutorial/Step8/MathFunctions/CMakeLists.txt +++ b/Help/guide/tutorial/Step8/MathFunctions/CMakeLists.txt @@ -1,10 +1,17 @@ -add_library(MathFunctions MathFunctions.cxx mysqrt.cxx) +add_library(MathFunctions MathFunctions.cxx) # should we use our own math functions option(USE_MYMATH "Use tutorial provided math implementation" ON) if (USE_MYMATH) target_compile_definitions(MathFunctions PRIVATE "USE_MYMATH") + # library that just does sqrt + add_library(SqrtLibrary STATIC + mysqrt.cxx + ) + + target_link_libraries(SqrtLibrary PUBLIC tutorial_compiler_flags) + # does this system provide the log and exp functions? include(CheckCXXSourceCompiles) check_cxx_source_compiles(" @@ -24,10 +31,12 @@ if (USE_MYMATH) # add compile definitions if(HAVE_LOG AND HAVE_EXP) - target_compile_definitions(MathFunctions + target_compile_definitions(SqrtLibrary PRIVATE "HAVE_LOG" "HAVE_EXP" ) endif() + + target_link_libraries(MathFunctions PRIVATE SqrtLibrary) endif() # state that anybody linking to us needs to include the current source dir @@ -41,6 +50,9 @@ target_link_libraries(MathFunctions PUBLIC tutorial_compiler_flags) # install libs set(installable_libs MathFunctions tutorial_compiler_flags) +if(TARGET SqrtLibrary) + list(APPEND installable_libs SqrtLibrary) +endif() install(TARGETS ${installable_libs} DESTINATION lib) # install include headers install(FILES MathFunctions.h DESTINATION include) diff --git a/Help/guide/tutorial/Step9/MathFunctions/CMakeLists.txt b/Help/guide/tutorial/Step9/MathFunctions/CMakeLists.txt index 05c8616..54cecf8 100644 --- a/Help/guide/tutorial/Step9/MathFunctions/CMakeLists.txt +++ b/Help/guide/tutorial/Step9/MathFunctions/CMakeLists.txt @@ -11,16 +11,8 @@ option(USE_MYMATH "Use tutorial provided math implementation" ON) if (USE_MYMATH) target_compile_definitions(MathFunctions PRIVATE "USE_MYMATH") - # first we add the executable that generates the table - add_executable(MakeTable MakeTable.cxx) - target_link_libraries(MakeTable PRIVATE tutorial_compiler_flags) - - # add the command to generate the source code - add_custom_command( - OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/Table.h - COMMAND MakeTable ${CMAKE_CURRENT_BINARY_DIR}/Table.h - DEPENDS MakeTable - ) + # generate Table.h + include(MakeTable.cmake) # library that just does sqrt add_library(SqrtLibrary STATIC @@ -30,8 +22,8 @@ if (USE_MYMATH) # state that we depend on our binary dir to find Table.h target_include_directories(SqrtLibrary PRIVATE - ${CMAKE_CURRENT_BINARY_DIR} - ) + ${CMAKE_CURRENT_BINARY_DIR} + ) target_link_libraries(SqrtLibrary PUBLIC tutorial_compiler_flags) target_link_libraries(MathFunctions PRIVATE SqrtLibrary) diff --git a/Help/guide/tutorial/Step9/MathFunctions/MakeTable.cmake b/Help/guide/tutorial/Step9/MathFunctions/MakeTable.cmake new file mode 100644 index 0000000..12865a9 --- /dev/null +++ b/Help/guide/tutorial/Step9/MathFunctions/MakeTable.cmake @@ -0,0 +1,10 @@ +# first we add the executable that generates the table +add_executable(MakeTable MakeTable.cxx) +target_link_libraries(MakeTable PRIVATE tutorial_compiler_flags) + +# add the command to generate the source code +add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/Table.h + COMMAND MakeTable ${CMAKE_CURRENT_BINARY_DIR}/Table.h + DEPENDS MakeTable + ) diff --git a/Help/manual/cmake-env-variables.7.rst b/Help/manual/cmake-env-variables.7.rst index 4c29b80..1f0c911 100644 --- a/Help/manual/cmake-env-variables.7.rst +++ b/Help/manual/cmake-env-variables.7.rst @@ -20,6 +20,7 @@ Environment Variables that Change Behavior .. toctree:: :maxdepth: 1 + /envvar/CMAKE_MAXIMUM_RECURSION_DEPTH /envvar/CMAKE_PREFIX_PATH /envvar/SSL_CERT_DIR /envvar/SSL_CERT_FILE diff --git a/Help/manual/cmake-generator-expressions.7.rst b/Help/manual/cmake-generator-expressions.7.rst index a640c13..9da3799 100644 --- a/Help/manual/cmake-generator-expressions.7.rst +++ b/Help/manual/cmake-generator-expressions.7.rst @@ -1418,6 +1418,7 @@ In the following, the phrase "the ``tgt`` filename" means the name of the expression is being evaluated. .. genex:: $<TARGET_PROPERTY:prop> + :target: TARGET_PROPERTY:prop Value of the property ``prop`` on the target for which the expression is being evaluated. Note that for generator expressions in diff --git a/Help/manual/cmake-policies.7.rst b/Help/manual/cmake-policies.7.rst index 28272ad..a37a45c 100644 --- a/Help/manual/cmake-policies.7.rst +++ b/Help/manual/cmake-policies.7.rst @@ -57,6 +57,8 @@ Policies Introduced by CMake 3.27 .. toctree:: :maxdepth: 1 + CMP0147: Visual Studio generators build custom commands in parallel. </policy/CMP0147> + CMP0146: The FindCUDA module is removed. </policy/CMP0146> CMP0145: The Dart and FindDart modules are removed. </policy/CMP0145> CMP0144: find_package uses upper-case PACKAGENAME_ROOT variables. </policy/CMP0144> diff --git a/Help/manual/cmake-properties.7.rst b/Help/manual/cmake-properties.7.rst index 01c9ce8..8559b0b 100644 --- a/Help/manual/cmake-properties.7.rst +++ b/Help/manual/cmake-properties.7.rst @@ -175,7 +175,10 @@ Properties on Targets /prop_tgt/CONFIG_POSTFIX /prop_tgt/CROSSCOMPILING_EMULATOR /prop_tgt/CUDA_ARCHITECTURES + /prop_tgt/CUDA_CUBIN_COMPILATION /prop_tgt/CUDA_EXTENSIONS + /prop_tgt/CUDA_FATBIN_COMPILATION + /prop_tgt/CUDA_OPTIX_COMPILATION /prop_tgt/CUDA_PTX_COMPILATION /prop_tgt/CUDA_RESOLVE_DEVICE_SYMBOLS /prop_tgt/CUDA_RUNTIME_LIBRARY diff --git a/Help/manual/cmake-toolchains.7.rst b/Help/manual/cmake-toolchains.7.rst index 8a83807..9feb4d2 100644 --- a/Help/manual/cmake-toolchains.7.rst +++ b/Help/manual/cmake-toolchains.7.rst @@ -84,7 +84,7 @@ Toolchain Features ================== CMake provides the :command:`try_compile` command and wrapper macros such as -:module:`CheckCXXSourceCompiles`, :module:`CheckCXXSymbolExists` and +:module:`CheckSourceCompiles`, :module:`CheckCXXSymbolExists` and :module:`CheckIncludeFile` to test capability and availability of various toolchain features. These APIs test the toolchain in some way and cache the result so that the test does not have to be performed again the next time diff --git a/Help/manual/cmake-variables.7.rst b/Help/manual/cmake-variables.7.rst index 99ea564..f3212de 100644 --- a/Help/manual/cmake-variables.7.rst +++ b/Help/manual/cmake-variables.7.rst @@ -132,6 +132,7 @@ Variables that Provide Information /variable/CMAKE_VS_TARGET_FRAMEWORK_TARGETS_VERSION /variable/CMAKE_VS_TARGET_FRAMEWORK_VERSION /variable/CMAKE_VS_VERSION_BUILD_NUMBER + /variable/CMAKE_VS_WINDOWS_TARGET_PLATFORM_MIN_VERSION /variable/CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION /variable/CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION_MAXIMUM /variable/CMAKE_XCODE_BUILD_SYSTEM @@ -403,11 +404,14 @@ Variables that Control the Build /variable/CMAKE_AUTOMOC_MACRO_NAMES /variable/CMAKE_AUTOMOC_MOC_OPTIONS /variable/CMAKE_AUTOMOC_PATH_PREFIX + /variable/CMAKE_AUTOMOC_EXECUTABLE /variable/CMAKE_AUTORCC /variable/CMAKE_AUTORCC_OPTIONS + /variable/CMAKE_AUTORCC_EXECUTABLE /variable/CMAKE_AUTOUIC /variable/CMAKE_AUTOUIC_OPTIONS /variable/CMAKE_AUTOUIC_SEARCH_PATHS + /variable/CMAKE_AUTOUIC_EXECUTABLE /variable/CMAKE_BUILD_RPATH /variable/CMAKE_BUILD_RPATH_USE_ORIGIN /variable/CMAKE_BUILD_WITH_INSTALL_NAME_DIR diff --git a/Help/module/CMAKE_REQUIRED_DEFINITIONS.txt b/Help/module/CMAKE_REQUIRED_DEFINITIONS.txt new file mode 100644 index 0000000..17289c3 --- /dev/null +++ b/Help/module/CMAKE_REQUIRED_DEFINITIONS.txt @@ -0,0 +1,4 @@ + ``CMAKE_REQUIRED_DEFINITIONS`` + A :ref:`;-list <CMake Language Lists>` of compiler definitions of the form + ``-DFOO`` or ``-DFOO=bar``. A definition for the name specified by + ``<resultVar>`` will also be added automatically. diff --git a/Help/module/CMAKE_REQUIRED_FLAGS.txt b/Help/module/CMAKE_REQUIRED_FLAGS.txt new file mode 100644 index 0000000..80ae239 --- /dev/null +++ b/Help/module/CMAKE_REQUIRED_FLAGS.txt @@ -0,0 +1,6 @@ + ``CMAKE_REQUIRED_FLAGS`` + String of additional flags to pass to the compiler. The string must be + space-delimited--a :ref:`;-list <CMake Language Lists>` will not work. + The contents of :variable:`CMAKE_<LANG>_FLAGS <CMAKE_<LANG>_FLAGS>` and + its associated configuration-specific variable are automatically added + to the compiler command before the contents of ``CMAKE_REQUIRED_FLAGS``. diff --git a/Help/module/CMAKE_REQUIRED_INCLUDES.txt b/Help/module/CMAKE_REQUIRED_INCLUDES.txt new file mode 100644 index 0000000..c8993bb --- /dev/null +++ b/Help/module/CMAKE_REQUIRED_INCLUDES.txt @@ -0,0 +1,4 @@ + ``CMAKE_REQUIRED_INCLUDES`` + A :ref:`;-list <CMake Language Lists>` of header search paths to pass to + the compiler. These will be the only header search paths used--the contents + of the :prop_dir:`INCLUDE_DIRECTORIES` directory property will be ignored. diff --git a/Help/module/CMAKE_REQUIRED_LIBRARIES.txt b/Help/module/CMAKE_REQUIRED_LIBRARIES.txt new file mode 100644 index 0000000..8611b9e --- /dev/null +++ b/Help/module/CMAKE_REQUIRED_LIBRARIES.txt @@ -0,0 +1,5 @@ + ``CMAKE_REQUIRED_LIBRARIES`` + A :ref:`;-list <CMake Language Lists>` of libraries to add to the link + command. These can be the name of system libraries or they can be + :ref:`Imported Targets <Imported Targets>` (see :command:`try_compile` for + further details). diff --git a/Help/module/CMAKE_REQUIRED_LINK_OPTIONS.txt b/Help/module/CMAKE_REQUIRED_LINK_OPTIONS.txt new file mode 100644 index 0000000..f2a2474 --- /dev/null +++ b/Help/module/CMAKE_REQUIRED_LINK_OPTIONS.txt @@ -0,0 +1,5 @@ + ``CMAKE_REQUIRED_LINK_OPTIONS`` + .. versionadded:: 3.14 + + A :ref:`;-list <CMake Language Lists>` of options to add to the link + command (see :command:`try_compile` for further details). diff --git a/Help/module/CMAKE_REQUIRED_QUIET.txt b/Help/module/CMAKE_REQUIRED_QUIET.txt new file mode 100644 index 0000000..aae8059 --- /dev/null +++ b/Help/module/CMAKE_REQUIRED_QUIET.txt @@ -0,0 +1,5 @@ + ``CMAKE_REQUIRED_QUIET`` + .. versionadded:: 3.1 + + If this variable evaluates to a boolean true value, all status messages + associated with the check will be suppressed. diff --git a/Help/policy/CMP0146.rst b/Help/policy/CMP0146.rst new file mode 100644 index 0000000..c7cac22 --- /dev/null +++ b/Help/policy/CMP0146.rst @@ -0,0 +1,29 @@ +CMP0146 +------- + +.. versionadded:: 3.27 + +The :module:`FindCUDA` module is removed. + +The :module:`FindCUDA` module has been deprecated since CMake 3.10. +CMake 3.27 and above prefer to not provide the module. +This policy provides compatibility for projects that have not been +ported away from it. + +Projects using the :module:`FindCUDA` module should be updated to use +CMake's first-class ``CUDA`` language support. List ``CUDA`` among the +languages named in the top-level call to the :command:`project` command, +or call the :command:`enable_language` command with ``CUDA``. +Then one can add CUDA (``.cu``) sources directly to targets, +similar to other languages. + +The ``OLD`` behavior of this policy is for ``find_package(CUDA)`` to +load the deprecated module. The ``NEW`` behavior is for uses of the +module to fail as if it does not exist. + +This policy was introduced in CMake version 3.27. CMake version +|release| warns when the policy is not set and uses ``OLD`` behavior. +Use the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` +explicitly. + +.. include:: DEPRECATED.txt diff --git a/Help/policy/CMP0147.rst b/Help/policy/CMP0147.rst new file mode 100644 index 0000000..0f25096 --- /dev/null +++ b/Help/policy/CMP0147.rst @@ -0,0 +1,24 @@ +CMP0147 +------- + +.. versionadded:: 3.27 + +:ref:`Visual Studio Generators` build custom commands in parallel. + +Visual Studio 15.8 (2017) and newer support building custom commands in +parallel. CMake 3.27 and above prefer to enable this behavior by adding +a ``BuildInParallel`` setting to custom commands in ``.vcxproj`` files. +This policy provides compatibility for projects that have not been updated +to expect this, e.g., because their custom commands were accidentally +relying on serial execution by MSBuild. + +The ``OLD`` behavior for this policy is to not add ``BuildInParallel``. +The ``NEW`` behavior for this policy is to add ``BuildInParallel`` for +VS 15.8 and newer. + +This policy was introduced in CMake version 3.27. Use the +:command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly. +Unlike many policies, CMake version |release| does *not* warn +when this policy is not set and simply uses ``OLD`` behavior. + +.. include:: DEPRECATED.txt diff --git a/Help/prop_tgt/COMPILE_OPTIONS.rst b/Help/prop_tgt/COMPILE_OPTIONS.rst index 0fd6aac..0dec250 100644 --- a/Help/prop_tgt/COMPILE_OPTIONS.rst +++ b/Help/prop_tgt/COMPILE_OPTIONS.rst @@ -11,6 +11,10 @@ The options will be added after after flags in the variables, but before those propagated from dependencies by the :prop_tgt:`INTERFACE_COMPILE_OPTIONS` property. +This property adds compile options for all languages in a target. +Use the :genex:`COMPILE_LANGUAGE` generator expression to specify +per-language compile options. + This property is initialized by the :prop_dir:`COMPILE_OPTIONS` directory property when a target is created, and is used by the generators to set the options for the compiler. diff --git a/Help/prop_tgt/CUDA_CUBIN_COMPILATION.rst b/Help/prop_tgt/CUDA_CUBIN_COMPILATION.rst new file mode 100644 index 0000000..f8860ae --- /dev/null +++ b/Help/prop_tgt/CUDA_CUBIN_COMPILATION.rst @@ -0,0 +1,14 @@ +CUDA_CUBIN_COMPILATION +---------------------- + +.. versionadded:: 3.27 + +Compile CUDA sources to ``.cubin`` files instead of ``.obj`` files +within :ref:`Object Libraries`. + +For example: + +.. code-block:: cmake + + add_library(mycubin OBJECT a.cu b.cu) + set_property(TARGET mycubin PROPERTY CUDA_CUBIN_COMPILATION ON) diff --git a/Help/prop_tgt/CUDA_FATBIN_COMPILATION.rst b/Help/prop_tgt/CUDA_FATBIN_COMPILATION.rst new file mode 100644 index 0000000..3d3c715 --- /dev/null +++ b/Help/prop_tgt/CUDA_FATBIN_COMPILATION.rst @@ -0,0 +1,14 @@ +CUDA_FATBIN_COMPILATION +----------------------- + +.. versionadded:: 3.27 + +Compile CUDA sources to ``.fatbin`` files instead of ``.obj`` files +within :ref:`Object Libraries`. + +For example: + +.. code-block:: cmake + + add_library(myfbins OBJECT a.cu b.cu) + set_property(TARGET myfbins PROPERTY CUDA_FATBIN_COMPILATION ON) diff --git a/Help/prop_tgt/CUDA_OPTIX_COMPILATION.rst b/Help/prop_tgt/CUDA_OPTIX_COMPILATION.rst new file mode 100644 index 0000000..c2a06a8 --- /dev/null +++ b/Help/prop_tgt/CUDA_OPTIX_COMPILATION.rst @@ -0,0 +1,14 @@ +CUDA_OPTIX_COMPILATION +---------------------- + +.. versionadded:: 3.27 + +Compile CUDA sources to ``.optixir`` files instead of ``.obj`` files +within :ref:`Object Libraries`. + +For example: + +.. code-block:: cmake + + add_library(myoptix OBJECT a.cu b.cu) + set_property(TARGET myoptix PROPERTY CUDA_OPTIX_COMPILATION ON) diff --git a/Help/prop_tgt/LANG_CLANG_TIDY.rst b/Help/prop_tgt/LANG_CLANG_TIDY.rst index 31f1876..1e10933 100644 --- a/Help/prop_tgt/LANG_CLANG_TIDY.rst +++ b/Help/prop_tgt/LANG_CLANG_TIDY.rst @@ -25,3 +25,8 @@ command line. This property is initialized by the value of the :variable:`CMAKE_<LANG>_CLANG_TIDY` variable if it is set when a target is created. + +.. versionadded:: 3.27 + + This property supports + :manual:`generator expressions <cmake-generator-expressions(7)>`. diff --git a/Help/prop_tgt/LANG_CPPCHECK.rst b/Help/prop_tgt/LANG_CPPCHECK.rst index 80acbc0..0b2dee6 100644 --- a/Help/prop_tgt/LANG_CPPCHECK.rst +++ b/Help/prop_tgt/LANG_CPPCHECK.rst @@ -15,3 +15,8 @@ tool returns non-zero. This property is initialized by the value of the :variable:`CMAKE_<LANG>_CPPCHECK` variable if it is set when a target is created. + +.. versionadded:: 3.27 + + This property supports + :manual:`generator expressions <cmake-generator-expressions(7)>`. diff --git a/Help/prop_tgt/LANG_CPPLINT.rst b/Help/prop_tgt/LANG_CPPLINT.rst index be6db46..38a1669 100644 --- a/Help/prop_tgt/LANG_CPPLINT.rst +++ b/Help/prop_tgt/LANG_CPPLINT.rst @@ -13,3 +13,8 @@ and report any problems. This property is initialized by the value of the :variable:`CMAKE_<LANG>_CPPLINT` variable if it is set when a target is created. + +.. versionadded:: 3.27 + + This property supports + :manual:`generator expressions <cmake-generator-expressions(7)>`. diff --git a/Help/prop_tgt/LANG_INCLUDE_WHAT_YOU_USE.rst b/Help/prop_tgt/LANG_INCLUDE_WHAT_YOU_USE.rst index eebef56..19b97f7 100644 --- a/Help/prop_tgt/LANG_INCLUDE_WHAT_YOU_USE.rst +++ b/Help/prop_tgt/LANG_INCLUDE_WHAT_YOU_USE.rst @@ -13,3 +13,8 @@ compiler and report a warning if the tool reports any problems. This property is initialized by the value of the :variable:`CMAKE_<LANG>_INCLUDE_WHAT_YOU_USE` variable if it is set when a target is created. + +.. versionadded:: 3.27 + + This property supports + :manual:`generator expressions <cmake-generator-expressions(7)>`. diff --git a/Help/prop_tgt/VS_WINDOWS_TARGET_PLATFORM_MIN_VERSION.rst b/Help/prop_tgt/VS_WINDOWS_TARGET_PLATFORM_MIN_VERSION.rst index 50cf203..ef3ceb0 100644 --- a/Help/prop_tgt/VS_WINDOWS_TARGET_PLATFORM_MIN_VERSION.rst +++ b/Help/prop_tgt/VS_WINDOWS_TARGET_PLATFORM_MIN_VERSION.rst @@ -7,6 +7,11 @@ Visual Studio Windows Target Platform Minimum Version For Windows 10. Specifies the minimum version of the OS that is being targeted. For example ``10.0.10240.0``. If the value is not specified, the -value of :variable:`CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION` will be used on -WindowsStore projects otherwise the target platform minimum version will not -be specified for the project. +value of the :variable:`CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION` variable +will be used on WindowsStore projects. Otherwise the target platform +minimum version will not be specified for the project. + +.. versionadded:: 3.27 + This property is initialized by the value of the + :variable:`CMAKE_VS_WINDOWS_TARGET_PLATFORM_MIN_VERSION` variable + if it is set when a target is created. diff --git a/Help/release/3.11.rst b/Help/release/3.11.rst index 957dd4f..6e1520a 100644 --- a/Help/release/3.11.rst +++ b/Help/release/3.11.rst @@ -174,7 +174,7 @@ Modules to removal of the ``javah`` tool by `JEP 313`_. .. _`FLAME`: https://github.com/flame -.. _`JEP 313`: https://openjdk.java.net/jeps/313 +.. _`JEP 313`: https://openjdk.org/jeps/313 Autogen ------- diff --git a/Help/release/3.24.rst b/Help/release/3.24.rst index f484e1a..e7ddf2a 100644 --- a/Help/release/3.24.rst +++ b/Help/release/3.24.rst @@ -380,3 +380,10 @@ Changes made since CMake 3.24.0 include the following. * Some implementation updates were made to support ecosystem changes and/or fix regressions. + +3.24.4 +------ + +* This version made no changes to documented features or interfaces. + Some implementation updates were made to support ecosystem changes + and/or fix regressions. diff --git a/Help/release/3.25.rst b/Help/release/3.25.rst index 2d04741..cb6984c 100644 --- a/Help/release/3.25.rst +++ b/Help/release/3.25.rst @@ -257,3 +257,10 @@ Changes made since CMake 3.25.0 include the following. * On Windows, the ``icpx`` compiler now provided by Intel oneAPI 2023.0 and above is no longer selected because its GNU-like command-line is not yet supported by CMake. + +3.25.3 +------ + +* This version made no changes to documented features or interfaces. + Some implementation updates were made to support ecosystem changes + and/or fix regressions. diff --git a/Help/release/3.26.rst b/Help/release/3.26.rst index ee98a98..67ace4a 100644 --- a/Help/release/3.26.rst +++ b/Help/release/3.26.rst @@ -169,3 +169,15 @@ Other Changes * The :option:`cmake --trace` option now follows :command:`try_compile` and :command:`try_run` invocations. + +Updates +======= + +Changes made since CMake 3.26.0 include the following. + +3.26.1, 3.26.2 +-------------- + +* These versions made no changes to documented features or interfaces. + Some implementation updates were made to support ecosystem changes + and/or fix regressions. diff --git a/Help/release/dev/FindCUDA-remove.rst b/Help/release/dev/FindCUDA-remove.rst new file mode 100644 index 0000000..e8b09d4 --- /dev/null +++ b/Help/release/dev/FindCUDA-remove.rst @@ -0,0 +1,6 @@ +FindCUDA-remove +--------------- + +* The :module:`FindCUDA` module has been fully deprecated via policy + :policy:`CMP0146`. Port projects to CMake's first-class ``CUDA`` + language support. diff --git a/Help/release/dev/FindCUDAToolkit-target-for-cudla.rst b/Help/release/dev/FindCUDAToolkit-target-for-cudla.rst new file mode 100644 index 0000000..9de456e --- /dev/null +++ b/Help/release/dev/FindCUDAToolkit-target-for-cudla.rst @@ -0,0 +1,4 @@ +FindCUDAToolkit-target-for-cudla +-------------------------------- + +* The :module:`FindCUDAToolkit` module now provides an imported target for ``cudla``, if found. diff --git a/Help/release/dev/FindOpenGL-gles.rst b/Help/release/dev/FindOpenGL-gles.rst new file mode 100644 index 0000000..fcbc516 --- /dev/null +++ b/Help/release/dev/FindOpenGL-gles.rst @@ -0,0 +1,5 @@ +FindOpenGL-gles +--------------- + +* The :module:`FindOpenGL` module gained support for components + ``GLES2`` and ``GLES3``. diff --git a/Help/release/dev/FindPython-Windows-ARM.rst b/Help/release/dev/FindPython-Windows-ARM.rst new file mode 100644 index 0000000..d88a65a --- /dev/null +++ b/Help/release/dev/FindPython-Windows-ARM.rst @@ -0,0 +1,5 @@ +FindPython-Windows-ARM +---------------------- + +* :module:`FindPython`, :module:`FindPython2` and :module:`FindPython3` modules + learn to manage ``Windows/ARM`` platform. diff --git a/Help/release/dev/FindwxWidgets-imported-target.rst b/Help/release/dev/FindwxWidgets-imported-target.rst new file mode 100644 index 0000000..c04e0ac --- /dev/null +++ b/Help/release/dev/FindwxWidgets-imported-target.rst @@ -0,0 +1,4 @@ +FindwxWidgets-imported-target +----------------------------- + +* The :module:`FindwxWidgets` module now provides an imported target. diff --git a/Help/release/dev/autogen-exe-vars.rst b/Help/release/dev/autogen-exe-vars.rst new file mode 100644 index 0000000..a386b4f --- /dev/null +++ b/Help/release/dev/autogen-exe-vars.rst @@ -0,0 +1,7 @@ +autogen-exe-vars +---------------- + +* The :variable:`CMAKE_AUTOMOC_EXECUTABLE`, + :variable:`CMAKE_AUTORCC_EXECUTABLE`, and + :variable:`CMAKE_AUTOUIC_EXECUTABLE` variables were added to initialize the + corresponding target properties as targets are created. diff --git a/Help/release/dev/cuda-support-new-compile-modes.rst b/Help/release/dev/cuda-support-new-compile-modes.rst new file mode 100644 index 0000000..2d24c16 --- /dev/null +++ b/Help/release/dev/cuda-support-new-compile-modes.rst @@ -0,0 +1,14 @@ +cuda-support-new-compile-modes +------------------------------ + +* A :prop_tgt:`CUDA_CUBIN_COMPILATION` target property was added to + :ref:`Object Libraries` to support compiling to ``.cubin`` files + instead of host object files. Currently only supported with NVIDIA. + +* A :prop_tgt:`CUDA_FATBIN_COMPILATION` target property was added to + :ref:`Object Libraries` to support compiling to ``.fatbin`` files + instead of host object files. Currently only supported with NVIDIA. + +* A :prop_tgt:`CUDA_OPTIX_COMPILATION` target property was added to + :ref:`Object Libraries` to support compiling to ``.optixir`` files + instead of host object files. Currently only supported with NVIDIA. diff --git a/Help/release/dev/cxx-module-extensions.rst b/Help/release/dev/cxx-module-extensions.rst new file mode 100644 index 0000000..92df86a --- /dev/null +++ b/Help/release/dev/cxx-module-extensions.rst @@ -0,0 +1,5 @@ +cxx-module-extensions +--------------------- + +* Source file extensions ``.ccm``, ``.cxxm``, or ``.c++m`` are now + treated as C++. diff --git a/Help/release/dev/file-GET_RUNTIME_DEPENDENCIES-windows-casing.rst b/Help/release/dev/file-GET_RUNTIME_DEPENDENCIES-windows-casing.rst new file mode 100644 index 0000000..858f8b3 --- /dev/null +++ b/Help/release/dev/file-GET_RUNTIME_DEPENDENCIES-windows-casing.rst @@ -0,0 +1,7 @@ +file-GET_RUNTIME_DEPENDENCIES-windows-casing +-------------------------------------------- + + +* The :command:`file(GET_RUNTIME_DEPENDENCIES)` command now case-preserves + DLL names reported on Windows. They are still converted to lowercase + for filter matching. diff --git a/Help/release/dev/lint-genex.rst b/Help/release/dev/lint-genex.rst new file mode 100644 index 0000000..8da30b0 --- /dev/null +++ b/Help/release/dev/lint-genex.rst @@ -0,0 +1,7 @@ +lint-genex +---------- + +* The :prop_tgt:`<LANG>_CLANG_TIDY`, :prop_tgt:`<LANG>_CPPCHECK`, + :prop_tgt:`<LANG>_CPPLINT`, and :prop_tgt:`<LANG>_INCLUDE_WHAT_YOU_USE`, + target properties now support + :manual:`generator expressions <cmake-generator-expressions(7)>`. diff --git a/Help/release/dev/vs-BuildInParallel.rst b/Help/release/dev/vs-BuildInParallel.rst new file mode 100644 index 0000000..ef344c7 --- /dev/null +++ b/Help/release/dev/vs-BuildInParallel.rst @@ -0,0 +1,5 @@ +vs-BuildInParallel +------------------ + +* :ref:`Visual Studio Generators`, for VS 15.8 (2017) and newer, now + build custom commands in parallel. See policy :policy:`CMP0147`. diff --git a/Help/release/dev/vs-windows-min-version.rst b/Help/release/dev/vs-windows-min-version.rst new file mode 100644 index 0000000..cb39159 --- /dev/null +++ b/Help/release/dev/vs-windows-min-version.rst @@ -0,0 +1,6 @@ +vs-windows-min-version +---------------------- + +* The :variable:`CMAKE_VS_WINDOWS_TARGET_PLATFORM_MIN_VERSION` variable + was added to initialize the :prop_tgt:`VS_WINDOWS_TARGET_PLATFORM_MIN_VERSION` + target property on all targets when they are created. diff --git a/Help/variable/CMAKE_AUTOMOC_EXECUTABLE.rst b/Help/variable/CMAKE_AUTOMOC_EXECUTABLE.rst new file mode 100644 index 0000000..150a73a --- /dev/null +++ b/Help/variable/CMAKE_AUTOMOC_EXECUTABLE.rst @@ -0,0 +1,10 @@ +CMAKE_AUTOMOC_EXECUTABLE +------------------------ + +.. versionadded:: 3.27 + +This variable is used to initialize the :prop_tgt:`AUTOMOC_EXECUTABLE` +property on all the targets. See that target property for additional +information. + +By default it is empty. diff --git a/Help/variable/CMAKE_AUTORCC_EXECUTABLE.rst b/Help/variable/CMAKE_AUTORCC_EXECUTABLE.rst new file mode 100644 index 0000000..52d7faa --- /dev/null +++ b/Help/variable/CMAKE_AUTORCC_EXECUTABLE.rst @@ -0,0 +1,10 @@ +CMAKE_AUTORCC_EXECUTABLE +------------------------ + +.. versionadded:: 3.27 + +This variable is used to initialize the :prop_tgt:`AUTORCC_EXECUTABLE` +property on all the targets. See that target property for additional +information. + +By default it is empty. diff --git a/Help/variable/CMAKE_AUTOUIC_EXECUTABLE.rst b/Help/variable/CMAKE_AUTOUIC_EXECUTABLE.rst new file mode 100644 index 0000000..b2ebd7f --- /dev/null +++ b/Help/variable/CMAKE_AUTOUIC_EXECUTABLE.rst @@ -0,0 +1,10 @@ +CMAKE_AUTOUIC_EXECUTABLE +------------------------ + +.. versionadded:: 3.27 + +This variable is used to initialize the :prop_tgt:`AUTOUIC_EXECUTABLE` +property on all the targets. See that target property for additional +information. + +By default it is empty. diff --git a/Help/variable/CMAKE_CROSSCOMPILING.rst b/Help/variable/CMAKE_CROSSCOMPILING.rst index 7e6ec33..16dbfa5 100644 --- a/Help/variable/CMAKE_CROSSCOMPILING.rst +++ b/Help/variable/CMAKE_CROSSCOMPILING.rst @@ -1,15 +1,15 @@ CMAKE_CROSSCOMPILING -------------------- -Intended to indicate whether CMake is cross compiling, but note limitations -discussed below. +This variable is set by CMake to indicate whether it is cross compiling, +but note limitations discussed below. This variable will be set to true by CMake if the :variable:`CMAKE_SYSTEM_NAME` variable has been set manually (i.e. in a toolchain file or as a cache entry from the :manual:`cmake <cmake(1)>` command line). In most cases, manually -setting :variable:`CMAKE_SYSTEM_NAME` will only be done when cross compiling, -since it will otherwise be given the same value as -:variable:`CMAKE_HOST_SYSTEM_NAME` if not manually set, which is correct for +setting :variable:`CMAKE_SYSTEM_NAME` will only be done when cross compiling +since, if not manually set, it will be given the same value as +:variable:`CMAKE_HOST_SYSTEM_NAME`, which is correct for the non-cross-compiling case. In the event that :variable:`CMAKE_SYSTEM_NAME` is manually set to the same value as :variable:`CMAKE_HOST_SYSTEM_NAME`, then ``CMAKE_CROSSCOMPILING`` will still be set to true. diff --git a/Help/variable/CMAKE_MAXIMUM_RECURSION_DEPTH.rst b/Help/variable/CMAKE_MAXIMUM_RECURSION_DEPTH.rst index 59c60d3..b611967 100644 --- a/Help/variable/CMAKE_MAXIMUM_RECURSION_DEPTH.rst +++ b/Help/variable/CMAKE_MAXIMUM_RECURSION_DEPTH.rst @@ -33,3 +33,5 @@ Calling any of the following commands increases the recursion depth: depth) * Reading or writing variables that are being watched by a :command:`variable_watch` + +See also the :envvar:`CMAKE_MAXIMUM_RECURSION_DEPTH` environment variable. diff --git a/Help/variable/CMAKE_VS_WINDOWS_TARGET_PLATFORM_MIN_VERSION.rst b/Help/variable/CMAKE_VS_WINDOWS_TARGET_PLATFORM_MIN_VERSION.rst new file mode 100644 index 0000000..8ef54cd --- /dev/null +++ b/Help/variable/CMAKE_VS_WINDOWS_TARGET_PLATFORM_MIN_VERSION.rst @@ -0,0 +1,12 @@ +CMAKE_VS_WINDOWS_TARGET_PLATFORM_MIN_VERSION +-------------------------------------------- + +.. versionadded:: 3.27 + +Tell :ref:`Visual Studio Generators` to use the given +Windows Target Platform Minimum Version. + +This variable is used to initialize the +:prop_tgt:`VS_WINDOWS_TARGET_PLATFORM_MIN_VERSION` property on all +targets when they are created. See that target property for +additional information. diff --git a/Modules/CMakeCUDAInformation.cmake b/Modules/CMakeCUDAInformation.cmake index dea721e..e774088 100644 --- a/Modules/CMakeCUDAInformation.cmake +++ b/Modules/CMakeCUDAInformation.cmake @@ -134,7 +134,6 @@ include(CMakeCommonLanguageInclude) # CMAKE_CUDA_CREATE_SHARED_LIBRARY # CMAKE_CUDA_CREATE_SHARED_MODULE # CMAKE_CUDA_COMPILE_WHOLE_COMPILATION -# CMAKE_CUDA_COMPILE_PTX_COMPILATION # CMAKE_CUDA_COMPILE_SEPARABLE_COMPILATION # CMAKE_CUDA_LINK_EXECUTABLE diff --git a/Modules/CMakeCXXCompiler.cmake.in b/Modules/CMakeCXXCompiler.cmake.in index dcfff6f..834c2e6 100644 --- a/Modules/CMakeCXXCompiler.cmake.in +++ b/Modules/CMakeCXXCompiler.cmake.in @@ -37,7 +37,7 @@ set(CMAKE_CXX_ABI_COMPILED @CMAKE_CXX_ABI_COMPILED@) set(CMAKE_CXX_COMPILER_ENV_VAR "CXX") set(CMAKE_CXX_COMPILER_ID_RUN 1) -set(CMAKE_CXX_SOURCE_FILE_EXTENSIONS C;M;c++;cc;cpp;cxx;m;mm;mpp;CPP;ixx;cppm) +set(CMAKE_CXX_SOURCE_FILE_EXTENSIONS C;M;c++;cc;cpp;cxx;m;mm;mpp;CPP;ixx;cppm;ccm;cxxm;c++m) set(CMAKE_CXX_IGNORE_EXTENSIONS inl;h;hpp;HPP;H;o;O;obj;OBJ;def;DEF;rc;RC) foreach (lang C OBJC OBJCXX) diff --git a/Modules/CMakeCheckCompilerFlagCommonPatterns.cmake b/Modules/CMakeCheckCompilerFlagCommonPatterns.cmake index cd978d5..bda1d71 100644 --- a/Modules/CMakeCheckCompilerFlagCommonPatterns.cmake +++ b/Modules/CMakeCheckCompilerFlagCommonPatterns.cmake @@ -12,7 +12,6 @@ macro (CHECK_COMPILER_FLAG_COMMON_PATTERNS _VAR) FAIL_REGEX "switch .* is no longer supported" # GNU FAIL_REGEX "unknown .*option" # Clang FAIL_REGEX "optimization flag .* not supported" # Clang - FAIL_REGEX "argument unused during compilation: .*" # Clang FAIL_REGEX "unknown argument ignored" # Clang (cl) FAIL_REGEX "ignoring unknown option" # MSVC, Intel FAIL_REGEX "warning D9002" # MSVC, any lang diff --git a/Modules/CMakeDetermineCompilerId.cmake b/Modules/CMakeDetermineCompilerId.cmake index 1f89c74..67044fb 100644 --- a/Modules/CMakeDetermineCompilerId.cmake +++ b/Modules/CMakeDetermineCompilerId.cmake @@ -401,6 +401,9 @@ Id flags: ${testflags} ${CMAKE_${lang}_COMPILER_ID_FLAGS_ALWAYS} endif() endif() set(id_toolset_version_props "<Import Project=\"${CMAKE_GENERATOR_INSTANCE}\\VC\\Auxiliary\\Build${id_sep}${CMAKE_VS_PLATFORM_TOOLSET_VERSION}\\Microsoft.VCToolsVersion.${CMAKE_VS_PLATFORM_TOOLSET_VERSION}.props\" />") + if(lang STREQUAL CXX OR lang STREQUAL C) + set(id_toolset_version_props "<Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />${id_toolset_version_props}") + endif() unset(id_sep) endif() endif() @@ -1144,7 +1147,7 @@ function(CMAKE_DETERMINE_MSVC_SHOWINCLUDES_PREFIX lang userflags) ENCODING AUTO # cl prints in console output code page ) string(REPLACE "\n" "\n " msg " ${out}") - if(res EQUAL 0 AND "${out}" MATCHES "(^|\n)([^:\n][^:\n]+:[^:\n]*[^: \n][^: \n]:?[ \t]+)[A-Za-z]:\\\\") + if(res EQUAL 0 AND "${out}" MATCHES "(^|\n)([^:\n][^:\n]+:[^:\n]*[^: \n][^: \n]:?[ \t]+)([A-Za-z]:\\\\|\\./)") set(CMAKE_${lang}_CL_SHOWINCLUDES_PREFIX "${CMAKE_MATCH_2}" PARENT_SCOPE) string(APPEND msg "\nFound prefix \"${CMAKE_MATCH_2}\"") else() diff --git a/Modules/CMakeDetermineSwiftCompiler.cmake b/Modules/CMakeDetermineSwiftCompiler.cmake index aaad560..f0a63a8 100644 --- a/Modules/CMakeDetermineSwiftCompiler.cmake +++ b/Modules/CMakeDetermineSwiftCompiler.cmake @@ -63,6 +63,65 @@ if(NOT CMAKE_Swift_COMPILER_ID_RUN) CMAKE_DETERMINE_COMPILER_ID(Swift "" CompilerId/main.swift) endif() +# Check if we are using the old compiler driver. +if(CMAKE_GENERATOR STREQUAL "Xcode") + # For Xcode, we can decide driver kind simply by Swift version. + if(CMAKE_Swift_COMPILER_VERSION VERSION_GREATER_EQUAL 5.5) + set(CMAKE_Swift_COMPILER_USE_OLD_DRIVER FALSE) + else() + set(CMAKE_Swift_COMPILER_USE_OLD_DRIVER TRUE) + endif() +elseif(NOT DEFINED CMAKE_Swift_COMPILER_USE_OLD_DRIVER) + # Dry-run a WMO build to identify the compiler driver. + + # Create a clean directory in which to run the test. + set(CMAKE_Swift_COMPILER_DRIVER_TEST_DIR ${CMAKE_PLATFORM_INFO_DIR}/SwiftCompilerDriver) + file(REMOVE_RECURSE "${CMAKE_Swift_COMPILER_DRIVER_TEST_DIR}") + file(MAKE_DIRECTORY "${CMAKE_Swift_COMPILER_DRIVER_TEST_DIR}") + + # Create a Swift file and an arbitrary linker resource. + file(WRITE ${CMAKE_Swift_COMPILER_DRIVER_TEST_DIR}/main.swift "print(\"Hello\")\n") + file(WRITE ${CMAKE_Swift_COMPILER_DRIVER_TEST_DIR}/lib.in "\n") + + # Honor user-specified compiler flags. + if(DEFINED CMAKE_Swift_FLAGS) + separate_arguments(_CMAKE_Swift_COMPILER_FLAGS_LIST NATIVE_COMMAND "${CMAKE_Swift_FLAGS}") + else() + separate_arguments(_CMAKE_Swift_COMPILER_FLAGS_LIST NATIVE_COMMAND "${CMAKE_Swift_FLAGS_INIT}") + endif() + set(_CMAKE_Swift_COMPILER_CHECK_COMMAND "${CMAKE_Swift_COMPILER}" ${_CMAKE_Swift_COMPILER_FLAGS_LIST} -wmo main.swift lib.in "-###") + unset(_CMAKE_Swift_COMPILER_FLAGS_LIST) + + # Execute in dry-run mode so no compilation will be actually performed. + execute_process(COMMAND ${_CMAKE_Swift_COMPILER_CHECK_COMMAND} + WORKING_DIRECTORY "${CMAKE_Swift_COMPILER_DRIVER_TEST_DIR}" + OUTPUT_VARIABLE _CMAKE_Swift_COMPILER_CHECK_OUTPUT) + + # Check the first frontend execution. It is on the first line of output. + # The old driver treats all inputs as Swift sources while the new driver + # can identify "lib.in" as a linker resource. + if("${_CMAKE_Swift_COMPILER_CHECK_OUTPUT}" MATCHES "^[^\n]* lib\\.in") + set(CMAKE_Swift_COMPILER_USE_OLD_DRIVER TRUE) + else() + set(CMAKE_Swift_COMPILER_USE_OLD_DRIVER FALSE) + endif() + + # Record the check results in the configure log. + list(TRANSFORM _CMAKE_Swift_COMPILER_CHECK_COMMAND PREPEND "\"") + list(TRANSFORM _CMAKE_Swift_COMPILER_CHECK_COMMAND APPEND "\"") + list(JOIN _CMAKE_Swift_COMPILER_CHECK_COMMAND " " _CMAKE_Swift_COMPILER_CHECK_COMMAND) + string(REPLACE "\n" "\n " _CMAKE_Swift_COMPILER_CHECK_OUTPUT " ${_CMAKE_Swift_COMPILER_CHECK_OUTPUT}") + message(CONFIGURE_LOG + "Detected CMAKE_Swift_COMPILER_USE_OLD_DRIVER=\"${CMAKE_Swift_COMPILER_USE_OLD_DRIVER}\" from:\n" + " ${_CMAKE_Swift_COMPILER_CHECK_COMMAND}\n" + "with output:\n" + "${_CMAKE_Swift_COMPILER_CHECK_OUTPUT}" + ) + + unset(_CMAKE_Swift_COMPILER_CHECK_COMMAND) + unset(_CMAKE_Swift_COMPILER_CHECK_OUTPUT) +endif() + if (NOT _CMAKE_TOOLCHAIN_LOCATION) get_filename_component(_CMAKE_TOOLCHAIN_LOCATION "${CMAKE_Swift_COMPILER}" PATH) endif () diff --git a/Modules/CMakeDetermineSystem.cmake b/Modules/CMakeDetermineSystem.cmake index d4dcc62..386be73 100644 --- a/Modules/CMakeDetermineSystem.cmake +++ b/Modules/CMakeDetermineSystem.cmake @@ -176,6 +176,13 @@ else() set(CMAKE_SYSTEM_VERSION "${CMAKE_HOST_SYSTEM_VERSION}") endif() set(CMAKE_SYSTEM_PROCESSOR "${CMAKE_HOST_SYSTEM_PROCESSOR}") + if(CMAKE_CROSSCOMPILING) + message(AUTHOR_WARNING + "CMAKE_CROSSCOMPILING has been set by the project, toolchain file, or user. " + "CMake is resetting it to false because CMAKE_SYSTEM_NAME was not set. " + "To indicate cross compilation, only CMAKE_SYSTEM_NAME needs to be set." + ) + endif() set(CMAKE_CROSSCOMPILING FALSE) set(PRESET_CMAKE_SYSTEM_NAME FALSE) endif() diff --git a/Modules/CMakeFortranCompiler.cmake.in b/Modules/CMakeFortranCompiler.cmake.in index b8b409a..fc81d0e 100644 --- a/Modules/CMakeFortranCompiler.cmake.in +++ b/Modules/CMakeFortranCompiler.cmake.in @@ -26,7 +26,7 @@ set(CMAKE_Fortran_COMPILER_ENV_VAR "FC") set(CMAKE_Fortran_COMPILER_SUPPORTS_F90 @CMAKE_Fortran_COMPILER_SUPPORTS_F90@) set(CMAKE_Fortran_COMPILER_ID_RUN 1) -set(CMAKE_Fortran_SOURCE_FILE_EXTENSIONS f;F;fpp;FPP;f77;F77;f90;F90;for;For;FOR;f95;F95@CMAKE_Fortran_VENDOR_SOURCE_FILE_EXTENSIONS@) +set(CMAKE_Fortran_SOURCE_FILE_EXTENSIONS f;F;fpp;FPP;f77;F77;f90;F90;for;For;FOR;f95;F95;f03;F03;f08;F08@CMAKE_Fortran_VENDOR_SOURCE_FILE_EXTENSIONS@) set(CMAKE_Fortran_IGNORE_EXTENSIONS h;H;o;O;obj;OBJ;def;DEF;rc;RC) set(CMAKE_Fortran_LINKER_PREFERENCE 20) if(UNIX) diff --git a/Modules/CMakeSwiftCompiler.cmake.in b/Modules/CMakeSwiftCompiler.cmake.in index 47ada38..b385190 100644 --- a/Modules/CMakeSwiftCompiler.cmake.in +++ b/Modules/CMakeSwiftCompiler.cmake.in @@ -13,4 +13,6 @@ set(CMAKE_Swift_COMPILER_ENV_VAR "SWIFTC") set(CMAKE_Swift_COMPILER_ID_RUN 1) set(CMAKE_Swift_SOURCE_FILE_EXTENSIONS swift) +set(CMAKE_Swift_COMPILER_USE_OLD_DRIVER "@CMAKE_Swift_COMPILER_USE_OLD_DRIVER@") + set(CMAKE_Swift_IMPLICIT_INCLUDE_DIRECTORIES "@CMAKE_Swift_IMPLICIT_INCLUDE_DIRECTORIES@") diff --git a/Modules/CMakeSwiftInformation.cmake b/Modules/CMakeSwiftInformation.cmake index d27aa3f..777c680 100644 --- a/Modules/CMakeSwiftInformation.cmake +++ b/Modules/CMakeSwiftInformation.cmake @@ -78,9 +78,17 @@ if(CMAKE_GENERATOR STREQUAL "Xcode") set(CMAKE_Swift_FLAGS_MINSIZEREL_INIT "-Osize") else() set(CMAKE_Swift_FLAGS_DEBUG_INIT "-Onone -g -incremental") - set(CMAKE_Swift_FLAGS_RELEASE_INIT "-O -wmo") - set(CMAKE_Swift_FLAGS_RELWITHDEBINFO_INIT "-O -g -wmo") - set(CMAKE_Swift_FLAGS_MINSIZEREL_INIT "-Osize -wmo") + set(CMAKE_Swift_FLAGS_RELEASE_INIT "-O") + set(CMAKE_Swift_FLAGS_RELWITHDEBINFO_INIT "-O -g") + set(CMAKE_Swift_FLAGS_MINSIZEREL_INIT "-Osize") + + # Enable Whole Module Optimization by default unless the old + # C++ driver is being used, which behaves differently under WMO. + if(NOT CMAKE_Swift_COMPILER_USE_OLD_DRIVER) + string(APPEND CMAKE_Swift_FLAGS_RELEASE_INIT " -wmo") + string(APPEND CMAKE_Swift_FLAGS_RELWITHDEBINFO_INIT " -wmo") + string(APPEND CMAKE_Swift_FLAGS_MINSIZEREL_INIT " -wmo") + endif() endif() if(CMAKE_EXECUTABLE_FORMAT STREQUAL "ELF") diff --git a/Modules/CheckCCompilerFlag.cmake b/Modules/CheckCCompilerFlag.cmake index 335b437..cd89a55 100644 --- a/Modules/CheckCCompilerFlag.cmake +++ b/Modules/CheckCCompilerFlag.cmake @@ -11,29 +11,40 @@ Check whether the C compiler supports a given flag. .. code-block:: cmake - check_c_compiler_flag(<flag> <var>) + check_c_compiler_flag(<flag> <resultVar>) Check that the ``<flag>`` is accepted by the compiler without a diagnostic. Stores the result in an internal cache entry - named ``<var>``. - -This command temporarily sets the ``CMAKE_REQUIRED_DEFINITIONS`` variable -and calls the ``check_c_source_compiles`` macro from the -:module:`CheckCSourceCompiles` module. See documentation of that -module for a listing of variables that can otherwise modify the build. + named ``<resultVar>``. A positive result from this check indicates only that the compiler did not issue a diagnostic message when given the flag. Whether the flag has any effect or even a specific one is beyond the scope of this module. -.. note:: - Since the :command:`try_compile` command forwards flags from variables - like :variable:`CMAKE_C_FLAGS <CMAKE_<LANG>_FLAGS>`, unknown flags - in such variables may cause a false negative for this check. +The check is only performed once, with the result cached in the variable named +by ``<resultVar>``. Every subsequent CMake run will re-use this cached value +rather than performing the check again, even if the ``<code>`` changes. In +order to force the check to be re-evaluated, the variable named by +``<resultVar>`` must be manually removed from the cache. + +The compile and link commands can be influenced by setting any of the +following variables prior to calling ``check_c_compiler_flag()`` + +.. include:: /module/CMAKE_REQUIRED_FLAGS.txt + +.. include:: /module/CMAKE_REQUIRED_DEFINITIONS.txt + +.. include:: /module/CMAKE_REQUIRED_INCLUDES.txt + +.. include:: /module/CMAKE_REQUIRED_LINK_OPTIONS.txt + +.. include:: /module/CMAKE_REQUIRED_LIBRARIES.txt + +.. include:: /module/CMAKE_REQUIRED_QUIET.txt + #]=======================================================================] include_guard(GLOBAL) -include(CheckCSourceCompiles) include(Internal/CheckCompilerFlag) macro (CHECK_C_COMPILER_FLAG _FLAG _RESULT) diff --git a/Modules/CheckCSourceCompiles.cmake b/Modules/CheckCSourceCompiles.cmake index b24da49..ce4719a 100644 --- a/Modules/CheckCSourceCompiles.cmake +++ b/Modules/CheckCSourceCompiles.cmake @@ -22,51 +22,27 @@ Check if given C source compiles and links into an executable. checking if anything in the output matches any of the specified regular expressions. - The underlying check is performed by the :command:`try_compile` command. The - compile and link commands can be influenced by setting any of the following - variables prior to calling ``check_c_source_compiles()``: - - ``CMAKE_REQUIRED_FLAGS`` - Additional flags to pass to the compiler. Note that the contents of - :variable:`CMAKE_C_FLAGS <CMAKE_<LANG>_FLAGS>` and its associated - configuration-specific variable are automatically added to the compiler - command before the contents of ``CMAKE_REQUIRED_FLAGS``. - - ``CMAKE_REQUIRED_DEFINITIONS`` - A :ref:`;-list <CMake Language Lists>` of compiler definitions of the form - ``-DFOO`` or ``-DFOO=bar``. A definition for the name specified by - ``<resultVar>`` will also be added automatically. - - ``CMAKE_REQUIRED_INCLUDES`` - A :ref:`;-list <CMake Language Lists>` of header search paths to pass to - the compiler. These will be the only header search paths used by - ``try_compile()``, i.e. the contents of the :prop_dir:`INCLUDE_DIRECTORIES` - directory property will be ignored. - - ``CMAKE_REQUIRED_LINK_OPTIONS`` - .. versionadded:: 3.14 - - A :ref:`;-list <CMake Language Lists>` of options to add to the link - command (see :command:`try_compile` for further details). - - ``CMAKE_REQUIRED_LIBRARIES`` - A :ref:`;-list <CMake Language Lists>` of libraries to add to the link - command. These can be the name of system libraries or they can be - :ref:`Imported Targets <Imported Targets>` (see :command:`try_compile` for - further details). - - ``CMAKE_REQUIRED_QUIET`` - .. versionadded:: 3.1 - - If this variable evaluates to a boolean true value, all status messages - associated with the check will be suppressed. - - The check is only performed once, with the result cached in the variable - named by ``<resultVar>``. Every subsequent CMake run will re-use this cached - value rather than performing the check again, even if the ``<code>`` changes. - In order to force the check to be re-evaluated, the variable named by + The check is only performed once, with the result cached in the variable named + by ``<resultVar>``. Every subsequent CMake run will re-use this cached value + rather than performing the check again, even if the ``<code>`` changes. In + order to force the check to be re-evaluated, the variable named by ``<resultVar>`` must be manually removed from the cache. + The compile and link commands can be influenced by setting any of the + following variables prior to calling ``check_c_source_compiles()``: + +.. include:: /module/CMAKE_REQUIRED_FLAGS.txt + +.. include:: /module/CMAKE_REQUIRED_DEFINITIONS.txt + +.. include:: /module/CMAKE_REQUIRED_INCLUDES.txt + +.. include:: /module/CMAKE_REQUIRED_LINK_OPTIONS.txt + +.. include:: /module/CMAKE_REQUIRED_LIBRARIES.txt + +.. include:: /module/CMAKE_REQUIRED_QUIET.txt + #]=======================================================================] include_guard(GLOBAL) diff --git a/Modules/CheckCSourceRuns.cmake b/Modules/CheckCSourceRuns.cmake index a6081ff..d5a8fda 100644 --- a/Modules/CheckCSourceRuns.cmake +++ b/Modules/CheckCSourceRuns.cmake @@ -21,51 +21,27 @@ subsequently be run. be set to 1, otherwise it will be set to an value that evaluates to boolean false (e.g. an empty string or an error message). - The underlying check is performed by the :command:`try_run` command. The - compile and link commands can be influenced by setting any of the following - variables prior to calling ``check_c_source_runs()``: - - ``CMAKE_REQUIRED_FLAGS`` - Additional flags to pass to the compiler. Note that the contents of - :variable:`CMAKE_C_FLAGS <CMAKE_<LANG>_FLAGS>` and its associated - configuration-specific variable are automatically added to the compiler - command before the contents of ``CMAKE_REQUIRED_FLAGS``. - - ``CMAKE_REQUIRED_DEFINITIONS`` - A :ref:`;-list <CMake Language Lists>` of compiler definitions of the form - ``-DFOO`` or ``-DFOO=bar``. A definition for the name specified by - ``<resultVar>`` will also be added automatically. - - ``CMAKE_REQUIRED_INCLUDES`` - A :ref:`;-list <CMake Language Lists>` of header search paths to pass to - the compiler. These will be the only header search paths used by - ``try_run()``, i.e. the contents of the :prop_dir:`INCLUDE_DIRECTORIES` - directory property will be ignored. - - ``CMAKE_REQUIRED_LINK_OPTIONS`` - .. versionadded:: 3.14 - - A :ref:`;-list <CMake Language Lists>` of options to add to the link - command (see :command:`try_run` for further details). - - ``CMAKE_REQUIRED_LIBRARIES`` - A :ref:`;-list <CMake Language Lists>` of libraries to add to the link - command. These can be the name of system libraries or they can be - :ref:`Imported Targets <Imported Targets>` (see :command:`try_run` for - further details). - - ``CMAKE_REQUIRED_QUIET`` - .. versionadded:: 3.1 - - If this variable evaluates to a boolean true value, all status messages - associated with the check will be suppressed. - - The check is only performed once, with the result cached in the variable - named by ``<resultVar>``. Every subsequent CMake run will re-use this cached - value rather than performing the check again, even if the ``<code>`` changes. - In order to force the check to be re-evaluated, the variable named by + The check is only performed once, with the result cached in the variable named + by ``<resultVar>``. Every subsequent CMake run will re-use this cached value + rather than performing the check again, even if the ``<code>`` changes. In + order to force the check to be re-evaluated, the variable named by ``<resultVar>`` must be manually removed from the cache. + The compile and link commands can be influenced by setting any of the + following variables prior to calling ``check_c_source_runs()``: + +.. include:: /module/CMAKE_REQUIRED_FLAGS.txt + +.. include:: /module/CMAKE_REQUIRED_DEFINITIONS.txt + +.. include:: /module/CMAKE_REQUIRED_INCLUDES.txt + +.. include:: /module/CMAKE_REQUIRED_LINK_OPTIONS.txt + +.. include:: /module/CMAKE_REQUIRED_LIBRARIES.txt + +.. include:: /module/CMAKE_REQUIRED_QUIET.txt + #]=======================================================================] include_guard(GLOBAL) diff --git a/Modules/CheckCXXCompilerFlag.cmake b/Modules/CheckCXXCompilerFlag.cmake index 3bc3463..a6884f5 100644 --- a/Modules/CheckCXXCompilerFlag.cmake +++ b/Modules/CheckCXXCompilerFlag.cmake @@ -17,11 +17,6 @@ Check whether the CXX compiler supports a given flag. a diagnostic. Stores the result in an internal cache entry named ``<var>``. -This command temporarily sets the ``CMAKE_REQUIRED_DEFINITIONS`` variable -and calls the ``check_cxx_source_compiles`` macro from the -:module:`CheckCXXSourceCompiles` module. See documentation of that -module for a listing of variables that can otherwise modify the build. - A positive result from this check indicates only that the compiler did not issue a diagnostic message when given the flag. Whether the flag has any effect or even a specific one is beyond the scope of this module. @@ -33,7 +28,6 @@ effect or even a specific one is beyond the scope of this module. #]=======================================================================] include_guard(GLOBAL) -include(CheckCXXSourceCompiles) include(Internal/CheckCompilerFlag) macro (CHECK_CXX_COMPILER_FLAG _FLAG _RESULT) diff --git a/Modules/CheckCXXSourceCompiles.cmake b/Modules/CheckCXXSourceCompiles.cmake index 502bfa7..4b33aa8 100644 --- a/Modules/CheckCXXSourceCompiles.cmake +++ b/Modules/CheckCXXSourceCompiles.cmake @@ -22,51 +22,27 @@ Check if given C++ source compiles and links into an executable. checking if anything in the output matches any of the specified regular expressions. - The underlying check is performed by the :command:`try_compile` command. The - compile and link commands can be influenced by setting any of the following - variables prior to calling ``check_cxx_source_compiles()``: - - ``CMAKE_REQUIRED_FLAGS`` - Additional flags to pass to the compiler. Note that the contents of - :variable:`CMAKE_CXX_FLAGS <CMAKE_<LANG>_FLAGS>` and its associated - configuration-specific variable are automatically added to the compiler - command before the contents of ``CMAKE_REQUIRED_FLAGS``. - - ``CMAKE_REQUIRED_DEFINITIONS`` - A :ref:`;-list <CMake Language Lists>` of compiler definitions of the form - ``-DFOO`` or ``-DFOO=bar``. A definition for the name specified by - ``<resultVar>`` will also be added automatically. - - ``CMAKE_REQUIRED_INCLUDES`` - A :ref:`;-list <CMake Language Lists>` of header search paths to pass to - the compiler. These will be the only header search paths used by - ``try_compile()``, i.e. the contents of the :prop_dir:`INCLUDE_DIRECTORIES` - directory property will be ignored. - - ``CMAKE_REQUIRED_LINK_OPTIONS`` - .. versionadded:: 3.14 - - A :ref:`;-list <CMake Language Lists>` of options to add to the link - command (see :command:`try_compile` for further details). - - ``CMAKE_REQUIRED_LIBRARIES`` - A :ref:`;-list <CMake Language Lists>` of libraries to add to the link - command. These can be the name of system libraries or they can be - :ref:`Imported Targets <Imported Targets>` (see :command:`try_compile` for - further details). - - ``CMAKE_REQUIRED_QUIET`` - .. versionadded:: 3.1 - - If this variable evaluates to a boolean true value, all status messages - associated with the check will be suppressed. - - The check is only performed once, with the result cached in the variable - named by ``<resultVar>``. Every subsequent CMake run will re-use this cached - value rather than performing the check again, even if the ``<code>`` changes. - In order to force the check to be re-evaluated, the variable named by + The check is only performed once, with the result cached in the variable named + by ``<resultVar>``. Every subsequent CMake run will re-use this cached value + rather than performing the check again, even if the ``<code>`` changes. In + order to force the check to be re-evaluated, the variable named by ``<resultVar>`` must be manually removed from the cache. + The compile and link commands can be influenced by setting any of the + following variables prior to calling ``check_cxx_source_compiles()``: + +.. include:: /module/CMAKE_REQUIRED_FLAGS.txt + +.. include:: /module/CMAKE_REQUIRED_DEFINITIONS.txt + +.. include:: /module/CMAKE_REQUIRED_INCLUDES.txt + +.. include:: /module/CMAKE_REQUIRED_LINK_OPTIONS.txt + +.. include:: /module/CMAKE_REQUIRED_LIBRARIES.txt + +.. include:: /module/CMAKE_REQUIRED_QUIET.txt + #]=======================================================================] include_guard(GLOBAL) diff --git a/Modules/CheckCXXSourceRuns.cmake b/Modules/CheckCXXSourceRuns.cmake index af03453..3402715 100644 --- a/Modules/CheckCXXSourceRuns.cmake +++ b/Modules/CheckCXXSourceRuns.cmake @@ -21,51 +21,27 @@ subsequently be run. be set to 1, otherwise it will be set to an value that evaluates to boolean false (e.g. an empty string or an error message). - The underlying check is performed by the :command:`try_run` command. The - compile and link commands can be influenced by setting any of the following - variables prior to calling ``check_cxx_source_runs()``: - - ``CMAKE_REQUIRED_FLAGS`` - Additional flags to pass to the compiler. Note that the contents of - :variable:`CMAKE_CXX_FLAGS <CMAKE_<LANG>_FLAGS>` and its associated - configuration-specific variable are automatically added to the compiler - command before the contents of ``CMAKE_REQUIRED_FLAGS``. - - ``CMAKE_REQUIRED_DEFINITIONS`` - A :ref:`;-list <CMake Language Lists>` of compiler definitions of the form - ``-DFOO`` or ``-DFOO=bar``. A definition for the name specified by - ``<resultVar>`` will also be added automatically. - - ``CMAKE_REQUIRED_INCLUDES`` - A :ref:`;-list <CMake Language Lists>` of header search paths to pass to - the compiler. These will be the only header search paths used by - ``try_run()``, i.e. the contents of the :prop_dir:`INCLUDE_DIRECTORIES` - directory property will be ignored. - - ``CMAKE_REQUIRED_LINK_OPTIONS`` - .. versionadded:: 3.14 - - A :ref:`;-list <CMake Language Lists>` of options to add to the link - command (see :command:`try_run` for further details). - - ``CMAKE_REQUIRED_LIBRARIES`` - A :ref:`;-list <CMake Language Lists>` of libraries to add to the link - command. These can be the name of system libraries or they can be - :ref:`Imported Targets <Imported Targets>` (see :command:`try_run` for - further details). - - ``CMAKE_REQUIRED_QUIET`` - .. versionadded:: 3.1 - - If this variable evaluates to a boolean true value, all status messages - associated with the check will be suppressed. - - The check is only performed once, with the result cached in the variable - named by ``<resultVar>``. Every subsequent CMake run will re-use this cached - value rather than performing the check again, even if the ``<code>`` changes. - In order to force the check to be re-evaluated, the variable named by + The check is only performed once, with the result cached in the variable named + by ``<resultVar>``. Every subsequent CMake run will re-use this cached value + rather than performing the check again, even if the ``<code>`` changes. In + order to force the check to be re-evaluated, the variable named by ``<resultVar>`` must be manually removed from the cache. + The compile and link commands can be influenced by setting any of the + following variables prior to calling ``check_cxx_source_runs()``: + +.. include:: /module/CMAKE_REQUIRED_FLAGS.txt + +.. include:: /module/CMAKE_REQUIRED_DEFINITIONS.txt + +.. include:: /module/CMAKE_REQUIRED_INCLUDES.txt + +.. include:: /module/CMAKE_REQUIRED_LINK_OPTIONS.txt + +.. include:: /module/CMAKE_REQUIRED_LIBRARIES.txt + +.. include:: /module/CMAKE_REQUIRED_QUIET.txt + #]=======================================================================] include_guard(GLOBAL) diff --git a/Modules/CheckCXXSymbolExists.cmake b/Modules/CheckCXXSymbolExists.cmake index 1fa0898..569dafd 100644 --- a/Modules/CheckCXXSymbolExists.cmake +++ b/Modules/CheckCXXSymbolExists.cmake @@ -41,22 +41,17 @@ Check if a symbol exists as a function, variable, or macro in ``C++``. The following variables may be set before calling this macro to modify the way the check is run: -``CMAKE_REQUIRED_FLAGS`` - string of compile command line flags. -``CMAKE_REQUIRED_DEFINITIONS`` - a :ref:`;-list <CMake Language Lists>` of macros to define (-DFOO=bar). -``CMAKE_REQUIRED_INCLUDES`` - a :ref:`;-list <CMake Language Lists>` of header search paths to pass to - the compiler. -``CMAKE_REQUIRED_LINK_OPTIONS`` - .. versionadded:: 3.14 - a :ref:`;-list <CMake Language Lists>` of options to add to the link command. -``CMAKE_REQUIRED_LIBRARIES`` - a :ref:`;-list <CMake Language Lists>` of libraries to add to the link - command. See policy :policy:`CMP0075`. -``CMAKE_REQUIRED_QUIET`` - .. versionadded:: 3.1 - execute quietly without messages. +.. include:: /module/CMAKE_REQUIRED_FLAGS.txt + +.. include:: /module/CMAKE_REQUIRED_DEFINITIONS.txt + +.. include:: /module/CMAKE_REQUIRED_INCLUDES.txt + +.. include:: /module/CMAKE_REQUIRED_LINK_OPTIONS.txt + +.. include:: /module/CMAKE_REQUIRED_LIBRARIES.txt + +.. include:: /module/CMAKE_REQUIRED_QUIET.txt For example: diff --git a/Modules/CheckCompilerFlag.cmake b/Modules/CheckCompilerFlag.cmake index 77c07b9..a18435b 100644 --- a/Modules/CheckCompilerFlag.cmake +++ b/Modules/CheckCompilerFlag.cmake @@ -13,24 +13,36 @@ Check whether the compiler supports a given flag. .. code-block:: cmake - check_compiler_flag(<lang> <flag> <var>) + check_compiler_flag(<lang> <flag> <resultVar>) Check that the ``<flag>`` is accepted by the compiler without a diagnostic. -Stores the result in an internal cache entry named ``<var>``. - -This command temporarily sets the ``CMAKE_REQUIRED_DEFINITIONS`` variable -and calls the ``check_source_compiles(<LANG>)`` function from the -:module:`CheckSourceCompiles` module. See documentation of that -module for a listing of variables that can otherwise modify the build. +Stores the result in an internal cache entry named ``<resultVar>``. A positive result from this check indicates only that the compiler did not issue a diagnostic message when given the flag. Whether the flag has any effect or even a specific one is beyond the scope of this module. -.. note:: - Since the :command:`try_compile` command forwards flags from variables - like :variable:`CMAKE_<LANG>_FLAGS <CMAKE_<LANG>_FLAGS>`, unknown flags - in such variables may cause a false negative for this check. +The check is only performed once, with the result cached in the variable named +by ``<resultVar>``. Every subsequent CMake run will re-use this cached value +rather than performing the check again, even if the ``<code>`` changes. In +order to force the check to be re-evaluated, the variable named by +``<resultVar>`` must be manually removed from the cache. + +The compile and link commands can be influenced by setting any of the +following variables prior to calling ``check_compiler_flag()`` + +.. include:: /module/CMAKE_REQUIRED_FLAGS.txt + +.. include:: /module/CMAKE_REQUIRED_DEFINITIONS.txt + +.. include:: /module/CMAKE_REQUIRED_INCLUDES.txt + +.. include:: /module/CMAKE_REQUIRED_LINK_OPTIONS.txt + +.. include:: /module/CMAKE_REQUIRED_LIBRARIES.txt + +.. include:: /module/CMAKE_REQUIRED_QUIET.txt + #]=======================================================================] include_guard(GLOBAL) diff --git a/Modules/CheckFortranCompilerFlag.cmake b/Modules/CheckFortranCompilerFlag.cmake index 5b1cd02..c3cd088 100644 --- a/Modules/CheckFortranCompilerFlag.cmake +++ b/Modules/CheckFortranCompilerFlag.cmake @@ -13,29 +13,40 @@ Check whether the Fortran compiler supports a given flag. .. code-block:: cmake - check_fortran_compiler_flag(<flag> <var>) + check_fortran_compiler_flag(<flag> <resultVar>) Check that the ``<flag>`` is accepted by the compiler without a diagnostic. Stores the result in an internal cache entry - named ``<var>``. - -This command temporarily sets the ``CMAKE_REQUIRED_DEFINITIONS`` variable -and calls the ``check_fortran_source_compiles`` macro from the -:module:`CheckFortranSourceCompiles` module. See documentation of that -module for a listing of variables that can otherwise modify the build. + named ``<resultVar>``. A positive result from this check indicates only that the compiler did not issue a diagnostic message when given the flag. Whether the flag has any effect or even a specific one is beyond the scope of this module. -.. note:: - Since the :command:`try_compile` command forwards flags from variables - like :variable:`CMAKE_Fortran_FLAGS <CMAKE_<LANG>_FLAGS>`, unknown flags - in such variables may cause a false negative for this check. +The check is only performed once, with the result cached in the variable named +by ``<resultVar>``. Every subsequent CMake run will re-use this cached value +rather than performing the check again, even if the ``<code>`` changes. In +order to force the check to be re-evaluated, the variable named by +``<resultVar>`` must be manually removed from the cache. + +The compile and link commands can be influenced by setting any of the +following variables prior to calling ``check_fortran_compiler_flag()`` + +.. include:: /module/CMAKE_REQUIRED_FLAGS.txt + +.. include:: /module/CMAKE_REQUIRED_DEFINITIONS.txt + +.. include:: /module/CMAKE_REQUIRED_INCLUDES.txt + +.. include:: /module/CMAKE_REQUIRED_LINK_OPTIONS.txt + +.. include:: /module/CMAKE_REQUIRED_LIBRARIES.txt + +.. include:: /module/CMAKE_REQUIRED_QUIET.txt + #]=======================================================================] include_guard(GLOBAL) -include(CheckFortranSourceCompiles) include(Internal/CheckCompilerFlag) macro (CHECK_FORTRAN_COMPILER_FLAG _FLAG _RESULT) diff --git a/Modules/CheckFortranSourceCompiles.cmake b/Modules/CheckFortranSourceCompiles.cmake index 8dcc1d5..5158b7e 100644 --- a/Modules/CheckFortranSourceCompiles.cmake +++ b/Modules/CheckFortranSourceCompiles.cmake @@ -47,49 +47,27 @@ Check if given Fortran source compiles and links into an executable. ``SRC_EXT`` option can be used to override this with ``.<extension>`` instead-- ``.F90`` is a typical choice. - The underlying check is performed by the :command:`try_compile` command. The - compile and link commands can be influenced by setting any of the following - variables prior to calling ``check_fortran_source_compiles()``: - - ``CMAKE_REQUIRED_FLAGS`` - Additional flags to pass to the compiler. Note that the contents of - :variable:`CMAKE_Fortran_FLAGS <CMAKE_<LANG>_FLAGS>` and its associated - configuration-specific variable are automatically added to the compiler - command before the contents of ``CMAKE_REQUIRED_FLAGS``. - - ``CMAKE_REQUIRED_DEFINITIONS`` - A :ref:`;-list <CMake Language Lists>` of compiler definitions of the form - ``-DFOO`` or ``-DFOO=bar``. A definition for the name specified by - ``<resultVar>`` will also be added automatically. - - ``CMAKE_REQUIRED_INCLUDES`` - A :ref:`;-list <CMake Language Lists>` of header search paths to pass to - the compiler. These will be the only header search paths used by - ``try_compile()``, i.e. the contents of the :prop_dir:`INCLUDE_DIRECTORIES` - directory property will be ignored. - - ``CMAKE_REQUIRED_LINK_OPTIONS`` - .. versionadded:: 3.14 - - A :ref:`;-list <CMake Language Lists>` of options to add to the link - command (see :command:`try_compile` for further details). - - ``CMAKE_REQUIRED_LIBRARIES`` - A :ref:`;-list <CMake Language Lists>` of libraries to add to the link - command. These can be the name of system libraries or they can be - :ref:`Imported Targets <Imported Targets>` (see :command:`try_compile` for - further details). - - ``CMAKE_REQUIRED_QUIET`` - If this variable evaluates to a boolean true value, all status messages - associated with the check will be suppressed. - - The check is only performed once, with the result cached in the variable - named by ``<resultVar>``. Every subsequent CMake run will re-use this cached - value rather than performing the check again, even if the ``<code>`` changes. - In order to force the check to be re-evaluated, the variable named by + The check is only performed once, with the result cached in the variable named + by ``<resultVar>``. Every subsequent CMake run will re-use this cached value + rather than performing the check again, even if the ``<code>`` changes. In + order to force the check to be re-evaluated, the variable named by ``<resultVar>`` must be manually removed from the cache. + The compile and link commands can be influenced by setting any of the + following variables prior to calling ``check_fortran_source_compiles()``: + +.. include:: /module/CMAKE_REQUIRED_FLAGS.txt + +.. include:: /module/CMAKE_REQUIRED_DEFINITIONS.txt + +.. include:: /module/CMAKE_REQUIRED_INCLUDES.txt + +.. include:: /module/CMAKE_REQUIRED_LINK_OPTIONS.txt + +.. include:: /module/CMAKE_REQUIRED_LIBRARIES.txt + +.. include:: /module/CMAKE_REQUIRED_QUIET.txt + #]=======================================================================] include_guard(GLOBAL) diff --git a/Modules/CheckFortranSourceRuns.cmake b/Modules/CheckFortranSourceRuns.cmake index 985c765..f996749 100644 --- a/Modules/CheckFortranSourceRuns.cmake +++ b/Modules/CheckFortranSourceRuns.cmake @@ -43,47 +43,27 @@ subsequently be run. By default, the test source file will be given a ``.F90`` file extension. The ``SRC_EXT`` option can be used to override this with ``.<extension>`` instead. - The underlying check is performed by the :command:`try_run` command. The - compile and link commands can be influenced by setting any of the following - variables prior to calling ``check_fortran_source_runs()``: - - ``CMAKE_REQUIRED_FLAGS`` - Additional flags to pass to the compiler. Note that the contents of - :variable:`CMAKE_Fortran_FLAGS <CMAKE_<LANG>_FLAGS>` and its associated - configuration-specific variable are automatically added to the compiler - command before the contents of ``CMAKE_REQUIRED_FLAGS``. - - ``CMAKE_REQUIRED_DEFINITIONS`` - A :ref:`;-list <CMake Language Lists>` of compiler definitions of the form - ``-DFOO`` or ``-DFOO=bar``. A definition for the name specified by - ``<resultVar>`` will also be added automatically. - - ``CMAKE_REQUIRED_INCLUDES`` - A :ref:`;-list <CMake Language Lists>` of header search paths to pass to - the compiler. These will be the only header search paths used by - ``try_run()``, i.e. the contents of the :prop_dir:`INCLUDE_DIRECTORIES` - directory property will be ignored. - - ``CMAKE_REQUIRED_LINK_OPTIONS`` - A :ref:`;-list <CMake Language Lists>` of options to add to the link - command (see :command:`try_run` for further details). - - ``CMAKE_REQUIRED_LIBRARIES`` - A :ref:`;-list <CMake Language Lists>` of libraries to add to the link - command. These can be the name of system libraries or they can be - :ref:`Imported Targets <Imported Targets>` (see :command:`try_run` for - further details). - - ``CMAKE_REQUIRED_QUIET`` - If this variable evaluates to a boolean true value, all status messages - associated with the check will be suppressed. - - The check is only performed once, with the result cached in the variable - named by ``<resultVar>``. Every subsequent CMake run will re-use this cached - value rather than performing the check again, even if the ``<code>`` changes. - In order to force the check to be re-evaluated, the variable named by + The check is only performed once, with the result cached in the variable named + by ``<resultVar>``. Every subsequent CMake run will re-use this cached value + rather than performing the check again, even if the ``<code>`` changes. In + order to force the check to be re-evaluated, the variable named by ``<resultVar>`` must be manually removed from the cache. + The compile and link commands can be influenced by setting any of the + following variables prior to calling ``check_fortran_source_runs()``: + +.. include:: /module/CMAKE_REQUIRED_FLAGS.txt + +.. include:: /module/CMAKE_REQUIRED_DEFINITIONS.txt + +.. include:: /module/CMAKE_REQUIRED_INCLUDES.txt + +.. include:: /module/CMAKE_REQUIRED_LINK_OPTIONS.txt + +.. include:: /module/CMAKE_REQUIRED_LIBRARIES.txt + +.. include:: /module/CMAKE_REQUIRED_QUIET.txt + #]=======================================================================] include_guard(GLOBAL) diff --git a/Modules/CheckFunctionExists.cmake b/Modules/CheckFunctionExists.cmake index e2939ed..e7c47a4 100644 --- a/Modules/CheckFunctionExists.cmake +++ b/Modules/CheckFunctionExists.cmake @@ -20,22 +20,17 @@ Check if a C function can be linked The following variables may be set before calling this macro to modify the way the check is run: -``CMAKE_REQUIRED_FLAGS`` - string of compile command line flags. -``CMAKE_REQUIRED_DEFINITIONS`` - a :ref:`;-list <CMake Language Lists>` of macros to define (-DFOO=bar). -``CMAKE_REQUIRED_INCLUDES`` - a :ref:`;-list <CMake Language Lists>` of header search paths to pass to - the compiler. -``CMAKE_REQUIRED_LINK_OPTIONS`` - .. versionadded:: 3.14 - a :ref:`;-list <CMake Language Lists>` of options to add to the link command. -``CMAKE_REQUIRED_LIBRARIES`` - a :ref:`;-list <CMake Language Lists>` of libraries to add to the link - command. See policy :policy:`CMP0075`. -``CMAKE_REQUIRED_QUIET`` - .. versionadded:: 3.1 - execute quietly without messages. +.. include:: /module/CMAKE_REQUIRED_FLAGS.txt + +.. include:: /module/CMAKE_REQUIRED_DEFINITIONS.txt + +.. include:: /module/CMAKE_REQUIRED_INCLUDES.txt + +.. include:: /module/CMAKE_REQUIRED_LINK_OPTIONS.txt + +.. include:: /module/CMAKE_REQUIRED_LIBRARIES.txt + +.. include:: /module/CMAKE_REQUIRED_QUIET.txt .. note:: diff --git a/Modules/CheckIncludeFile.cmake b/Modules/CheckIncludeFile.cmake index 5771307..1d8c9f7 100644 --- a/Modules/CheckIncludeFile.cmake +++ b/Modules/CheckIncludeFile.cmake @@ -21,22 +21,17 @@ Provides a macro to check if a header file can be included in ``C``. The following variables may be set before calling this macro to modify the way the check is run: -``CMAKE_REQUIRED_FLAGS`` - string of compile command line flags. -``CMAKE_REQUIRED_DEFINITIONS`` - a :ref:`;-list <CMake Language Lists>` of macros to define (-DFOO=bar). -``CMAKE_REQUIRED_INCLUDES`` - a :ref:`;-list <CMake Language Lists>` of header search paths to pass to - the compiler. -``CMAKE_REQUIRED_LINK_OPTIONS`` - .. versionadded:: 3.14 - a :ref:`;-list <CMake Language Lists>` of options to add to the link command. -``CMAKE_REQUIRED_LIBRARIES`` - a :ref:`;-list <CMake Language Lists>` of libraries to add to the link - command. See policy :policy:`CMP0075`. -``CMAKE_REQUIRED_QUIET`` - .. versionadded:: 3.1 - execute quietly without messages. +.. include:: /module/CMAKE_REQUIRED_FLAGS.txt + +.. include:: /module/CMAKE_REQUIRED_DEFINITIONS.txt + +.. include:: /module/CMAKE_REQUIRED_INCLUDES.txt + +.. include:: /module/CMAKE_REQUIRED_LINK_OPTIONS.txt + +.. include:: /module/CMAKE_REQUIRED_LIBRARIES.txt + +.. include:: /module/CMAKE_REQUIRED_QUIET.txt See the :module:`CheckIncludeFiles` module to check for multiple headers at once. See the :module:`CheckIncludeFileCXX` module to check for headers diff --git a/Modules/CheckIncludeFileCXX.cmake b/Modules/CheckIncludeFileCXX.cmake index d27b485..53d9a45 100644 --- a/Modules/CheckIncludeFileCXX.cmake +++ b/Modules/CheckIncludeFileCXX.cmake @@ -21,22 +21,17 @@ Provides a macro to check if a header file can be included in ``CXX``. The following variables may be set before calling this macro to modify the way the check is run: -``CMAKE_REQUIRED_FLAGS`` - string of compile command line flags. -``CMAKE_REQUIRED_DEFINITIONS`` - a :ref:`;-list <CMake Language Lists>` of macros to define (-DFOO=bar). -``CMAKE_REQUIRED_INCLUDES`` - a :ref:`;-list <CMake Language Lists>` of header search paths to pass to - the compiler. -``CMAKE_REQUIRED_LINK_OPTIONS`` - .. versionadded:: 3.14 - a :ref:`;-list <CMake Language Lists>` of options to add to the link command. -``CMAKE_REQUIRED_LIBRARIES`` - a :ref:`;-list <CMake Language Lists>` of libraries to add to the link - command. See policy :policy:`CMP0075`. -``CMAKE_REQUIRED_QUIET`` - .. versionadded:: 3.1 - execute quietly without messages. +.. include:: /module/CMAKE_REQUIRED_FLAGS.txt + +.. include:: /module/CMAKE_REQUIRED_DEFINITIONS.txt + +.. include:: /module/CMAKE_REQUIRED_INCLUDES.txt + +.. include:: /module/CMAKE_REQUIRED_LINK_OPTIONS.txt + +.. include:: /module/CMAKE_REQUIRED_LIBRARIES.txt + +.. include:: /module/CMAKE_REQUIRED_QUIET.txt See modules :module:`CheckIncludeFile` and :module:`CheckIncludeFiles` to check for one or more ``C`` headers. diff --git a/Modules/CheckIncludeFiles.cmake b/Modules/CheckIncludeFiles.cmake index 2f50c61..071df0c 100644 --- a/Modules/CheckIncludeFiles.cmake +++ b/Modules/CheckIncludeFiles.cmake @@ -27,22 +27,17 @@ be included together. The following variables may be set before calling this macro to modify the way the check is run: -``CMAKE_REQUIRED_FLAGS`` - string of compile command line flags. -``CMAKE_REQUIRED_DEFINITIONS`` - a :ref:`;-list <CMake Language Lists>` of macros to define (-DFOO=bar). -``CMAKE_REQUIRED_INCLUDES`` - a :ref:`;-list <CMake Language Lists>` of header search paths to pass to - the compiler. -``CMAKE_REQUIRED_LINK_OPTIONS`` - .. versionadded:: 3.14 - a :ref:`;-list <CMake Language Lists>` of options to add to the link command. -``CMAKE_REQUIRED_LIBRARIES`` - a :ref:`;-list <CMake Language Lists>` of libraries to add to the link - command. See policy :policy:`CMP0075`. -``CMAKE_REQUIRED_QUIET`` - .. versionadded:: 3.1 - execute quietly without messages. +.. include:: /module/CMAKE_REQUIRED_FLAGS.txt + +.. include:: /module/CMAKE_REQUIRED_DEFINITIONS.txt + +.. include:: /module/CMAKE_REQUIRED_INCLUDES.txt + +.. include:: /module/CMAKE_REQUIRED_LINK_OPTIONS.txt + +.. include:: /module/CMAKE_REQUIRED_LIBRARIES.txt + +.. include:: /module/CMAKE_REQUIRED_QUIET.txt See modules :module:`CheckIncludeFile` and :module:`CheckIncludeFileCXX` to check for a single header file in ``C`` or ``CXX`` languages. diff --git a/Modules/CheckLanguage.cmake b/Modules/CheckLanguage.cmake index 2e56a19..69913a3 100644 --- a/Modules/CheckLanguage.cmake +++ b/Modules/CheckLanguage.cmake @@ -36,7 +36,7 @@ Example: include_guard(GLOBAL) -cmake_policy(PUSH) +block(SCOPE_FOR POLICIES) cmake_policy(SET CMP0126 NEW) macro(check_language lang) @@ -114,4 +114,4 @@ file(WRITE \"\${CMAKE_CURRENT_BINARY_DIR}/result.cmake\" endif() endmacro() -cmake_policy(POP) +endblock() diff --git a/Modules/CheckLibraryExists.cmake b/Modules/CheckLibraryExists.cmake index 5f1a914..8340500 100644 --- a/Modules/CheckLibraryExists.cmake +++ b/Modules/CheckLibraryExists.cmake @@ -26,18 +26,16 @@ Check if the function exists. The following variables may be set before calling this macro to modify the way the check is run: -``CMAKE_REQUIRED_FLAGS`` - string of compile command line flags. -``CMAKE_REQUIRED_DEFINITIONS`` - list of macros to define (-DFOO=bar). -``CMAKE_REQUIRED_LINK_OPTIONS`` - .. versionadded:: 3.14 - list of options to pass to link command. -``CMAKE_REQUIRED_LIBRARIES`` - list of libraries to link. -``CMAKE_REQUIRED_QUIET`` - .. versionadded:: 3.1 - execute quietly without messages. +.. include:: /module/CMAKE_REQUIRED_FLAGS.txt + +.. include:: /module/CMAKE_REQUIRED_DEFINITIONS.txt + +.. include:: /module/CMAKE_REQUIRED_LINK_OPTIONS.txt + +.. include:: /module/CMAKE_REQUIRED_LIBRARIES.txt + +.. include:: /module/CMAKE_REQUIRED_QUIET.txt + #]=======================================================================] include_guard(GLOBAL) diff --git a/Modules/CheckOBJCCompilerFlag.cmake b/Modules/CheckOBJCCompilerFlag.cmake index d8d8741..ceb7e17 100644 --- a/Modules/CheckOBJCCompilerFlag.cmake +++ b/Modules/CheckOBJCCompilerFlag.cmake @@ -13,29 +13,40 @@ Check whether the Objective-C compiler supports a given flag. .. code-block:: cmake - check_objc_compiler_flag(<flag> <var>) + check_objc_compiler_flag(<flag> <resultVar>) Check that the ``<flag>`` is accepted by the compiler without a diagnostic. Stores the result in an internal cache entry - named ``<var>``. - -This command temporarily sets the ``CMAKE_REQUIRED_DEFINITIONS`` variable -and calls the ``check_objc_source_compiles`` macro from the -:module:`CheckOBJCSourceCompiles` module. See documentation of that -module for a listing of variables that can otherwise modify the build. + named ``<resultVar>``. A positive result from this check indicates only that the compiler did not issue a diagnostic message when given the flag. Whether the flag has any effect or even a specific one is beyond the scope of this module. -.. note:: - Since the :command:`try_compile` command forwards flags from variables - like :variable:`CMAKE_OBJC_FLAGS <CMAKE_<LANG>_FLAGS>`, unknown flags - in such variables may cause a false negative for this check. +The check is only performed once, with the result cached in the variable named +by ``<resultVar>``. Every subsequent CMake run will re-use this cached value +rather than performing the check again, even if the ``<code>`` changes. In +order to force the check to be re-evaluated, the variable named by +``<resultVar>`` must be manually removed from the cache. + +The compile and link commands can be influenced by setting any of the +following variables prior to calling ``check_objc_compiler_flag()`` + +.. include:: /module/CMAKE_REQUIRED_FLAGS.txt + +.. include:: /module/CMAKE_REQUIRED_DEFINITIONS.txt + +.. include:: /module/CMAKE_REQUIRED_INCLUDES.txt + +.. include:: /module/CMAKE_REQUIRED_LINK_OPTIONS.txt + +.. include:: /module/CMAKE_REQUIRED_LIBRARIES.txt + +.. include:: /module/CMAKE_REQUIRED_QUIET.txt + #]=======================================================================] include_guard(GLOBAL) -include(CheckOBJCSourceCompiles) include(Internal/CheckCompilerFlag) macro (CHECK_OBJC_COMPILER_FLAG _FLAG _RESULT) diff --git a/Modules/CheckOBJCSourceCompiles.cmake b/Modules/CheckOBJCSourceCompiles.cmake index c268ef9..7663054 100644 --- a/Modules/CheckOBJCSourceCompiles.cmake +++ b/Modules/CheckOBJCSourceCompiles.cmake @@ -24,47 +24,27 @@ Check if given Objective-C source compiles and links into an executable. checking if anything in the output matches any of the specified regular expressions. - The underlying check is performed by the :command:`try_compile` command. The - compile and link commands can be influenced by setting any of the following - variables prior to calling ``check_objc_source_compiles()``: - - ``CMAKE_REQUIRED_FLAGS`` - Additional flags to pass to the compiler. Note that the contents of - :variable:`CMAKE_OBJC_FLAGS <CMAKE_<LANG>_FLAGS>` and its associated - configuration-specific variable are automatically added to the compiler - command before the contents of ``CMAKE_REQUIRED_FLAGS``. - - ``CMAKE_REQUIRED_DEFINITIONS`` - A :ref:`;-list <CMake Language Lists>` of compiler definitions of the form - ``-DFOO`` or ``-DFOO=bar``. A definition for the name specified by - ``<resultVar>`` will also be added automatically. - - ``CMAKE_REQUIRED_INCLUDES`` - A :ref:`;-list <CMake Language Lists>` of header search paths to pass to - the compiler. These will be the only header search paths used by - ``try_compile()``, i.e. the contents of the :prop_dir:`INCLUDE_DIRECTORIES` - directory property will be ignored. - - ``CMAKE_REQUIRED_LINK_OPTIONS`` - A :ref:`;-list <CMake Language Lists>` of options to add to the link - command (see :command:`try_compile` for further details). - - ``CMAKE_REQUIRED_LIBRARIES`` - A :ref:`;-list <CMake Language Lists>` of libraries to add to the link - command. These can be the name of system libraries or they can be - :ref:`Imported Targets <Imported Targets>` (see :command:`try_compile` for - further details). - - ``CMAKE_REQUIRED_QUIET`` - If this variable evaluates to a boolean true value, all status messages - associated with the check will be suppressed. - - The check is only performed once, with the result cached in the variable - named by ``<resultVar>``. Every subsequent CMake run will re-use this cached - value rather than performing the check again, even if the ``<code>`` changes. - In order to force the check to be re-evaluated, the variable named by + The check is only performed once, with the result cached in the variable named + by ``<resultVar>``. Every subsequent CMake run will re-use this cached value + rather than performing the check again, even if the ``<code>`` changes. In + order to force the check to be re-evaluated, the variable named by ``<resultVar>`` must be manually removed from the cache. + The compile and link commands can be influenced by setting any of the + following variables prior to calling ``check_objc_source_compiles()`` + +.. include:: /module/CMAKE_REQUIRED_FLAGS.txt + +.. include:: /module/CMAKE_REQUIRED_DEFINITIONS.txt + +.. include:: /module/CMAKE_REQUIRED_INCLUDES.txt + +.. include:: /module/CMAKE_REQUIRED_LINK_OPTIONS.txt + +.. include:: /module/CMAKE_REQUIRED_LIBRARIES.txt + +.. include:: /module/CMAKE_REQUIRED_QUIET.txt + #]=======================================================================] include_guard(GLOBAL) diff --git a/Modules/CheckOBJCSourceRuns.cmake b/Modules/CheckOBJCSourceRuns.cmake index dd03309..a23a0c7 100644 --- a/Modules/CheckOBJCSourceRuns.cmake +++ b/Modules/CheckOBJCSourceRuns.cmake @@ -23,47 +23,27 @@ subsequently be run. be set to 1, otherwise it will be set to an value that evaluates to boolean false (e.g. an empty string or an error message). - The underlying check is performed by the :command:`try_run` command. The - compile and link commands can be influenced by setting any of the following - variables prior to calling ``check_objc_source_runs()``: - - ``CMAKE_REQUIRED_FLAGS`` - Additional flags to pass to the compiler. Note that the contents of - :variable:`CMAKE_OBJC_FLAGS <CMAKE_<LANG>_FLAGS>` and its associated - configuration-specific variable are automatically added to the compiler - command before the contents of ``CMAKE_REQUIRED_FLAGS``. - - ``CMAKE_REQUIRED_DEFINITIONS`` - A :ref:`;-list <CMake Language Lists>` of compiler definitions of the form - ``-DFOO`` or ``-DFOO=bar``. A definition for the name specified by - ``<resultVar>`` will also be added automatically. - - ``CMAKE_REQUIRED_INCLUDES`` - A :ref:`;-list <CMake Language Lists>` of header search paths to pass to - the compiler. These will be the only header search paths used by - ``try_run()``, i.e. the contents of the :prop_dir:`INCLUDE_DIRECTORIES` - directory property will be ignored. - - ``CMAKE_REQUIRED_LINK_OPTIONS`` - A :ref:`;-list <CMake Language Lists>` of options to add to the link - command (see :command:`try_run` for further details). - - ``CMAKE_REQUIRED_LIBRARIES`` - A :ref:`;-list <CMake Language Lists>` of libraries to add to the link - command. These can be the name of system libraries or they can be - :ref:`Imported Targets <Imported Targets>` (see :command:`try_run` for - further details). - - ``CMAKE_REQUIRED_QUIET`` - If this variable evaluates to a boolean true value, all status messages - associated with the check will be suppressed. - - The check is only performed once, with the result cached in the variable - named by ``<resultVar>``. Every subsequent CMake run will re-use this cached - value rather than performing the check again, even if the ``<code>`` changes. - In order to force the check to be re-evaluated, the variable named by + The check is only performed once, with the result cached in the variable named + by ``<resultVar>``. Every subsequent CMake run will re-use this cached value + rather than performing the check again, even if the ``<code>`` changes. In + order to force the check to be re-evaluated, the variable named by ``<resultVar>`` must be manually removed from the cache. + The compile and link commands can be influenced by setting any of the + following variables prior to calling ``check_objc_source_runs()`` + +.. include:: /module/CMAKE_REQUIRED_FLAGS.txt + +.. include:: /module/CMAKE_REQUIRED_DEFINITIONS.txt + +.. include:: /module/CMAKE_REQUIRED_INCLUDES.txt + +.. include:: /module/CMAKE_REQUIRED_LINK_OPTIONS.txt + +.. include:: /module/CMAKE_REQUIRED_LIBRARIES.txt + +.. include:: /module/CMAKE_REQUIRED_QUIET.txt + #]=======================================================================] include_guard(GLOBAL) diff --git a/Modules/CheckOBJCXXCompilerFlag.cmake b/Modules/CheckOBJCXXCompilerFlag.cmake index 3f3f8fe..47dacc2 100644 --- a/Modules/CheckOBJCXXCompilerFlag.cmake +++ b/Modules/CheckOBJCXXCompilerFlag.cmake @@ -13,29 +13,40 @@ Check whether the Objective-C++ compiler supports a given flag. .. code-block:: cmake - check_objcxx_compiler_flag(<flag> <var>) + check_objcxx_compiler_flag(<flag> <resultVar>) Check that the ``<flag>`` is accepted by the compiler without a diagnostic. Stores the result in an internal cache entry - named ``<var>``. - -This command temporarily sets the ``CMAKE_REQUIRED_DEFINITIONS`` variable -and calls the ``check_objcxx_source_compiles`` macro from the -:module:`CheckOBJCXXSourceCompiles` module. See documentation of that -module for a listing of variables that can otherwise modify the build. + named ``<resultVar>``. A positive result from this check indicates only that the compiler did not issue a diagnostic message when given the flag. Whether the flag has any effect or even a specific one is beyond the scope of this module. -.. note:: - Since the :command:`try_compile` command forwards flags from variables - like :variable:`CMAKE_OBJCXX_FLAGS <CMAKE_<LANG>_FLAGS>`, unknown flags - in such variables may cause a false negative for this check. +The check is only performed once, with the result cached in the variable named +by ``<resultVar>``. Every subsequent CMake run will re-use this cached value +rather than performing the check again, even if the ``<code>`` changes. In +order to force the check to be re-evaluated, the variable named by +``<resultVar>`` must be manually removed from the cache. + +The compile and link commands can be influenced by setting any of the +following variables prior to calling ``check_objcxx_compiler_flag()`` + +.. include:: /module/CMAKE_REQUIRED_FLAGS.txt + +.. include:: /module/CMAKE_REQUIRED_DEFINITIONS.txt + +.. include:: /module/CMAKE_REQUIRED_INCLUDES.txt + +.. include:: /module/CMAKE_REQUIRED_LINK_OPTIONS.txt + +.. include:: /module/CMAKE_REQUIRED_LIBRARIES.txt + +.. include:: /module/CMAKE_REQUIRED_QUIET.txt + #]=======================================================================] include_guard(GLOBAL) -include(CheckOBJCXXSourceCompiles) include(Internal/CheckCompilerFlag) macro (CHECK_OBJCXX_COMPILER_FLAG _FLAG _RESULT) diff --git a/Modules/CheckOBJCXXSourceCompiles.cmake b/Modules/CheckOBJCXXSourceCompiles.cmake index 1186934..cfbda3a 100644 --- a/Modules/CheckOBJCXXSourceCompiles.cmake +++ b/Modules/CheckOBJCXXSourceCompiles.cmake @@ -24,47 +24,27 @@ Check if given Objective-C++ source compiles and links into an executable. checking if anything in the output matches any of the specified regular expressions. - The underlying check is performed by the :command:`try_compile` command. The - compile and link commands can be influenced by setting any of the following - variables prior to calling ``check_objcxx_source_compiles()``: - - ``CMAKE_REQUIRED_FLAGS`` - Additional flags to pass to the compiler. Note that the contents of - :variable:`CMAKE_OBJCXX_FLAGS <CMAKE_<LANG>_FLAGS>` and its associated - configuration-specific variable are automatically added to the compiler - command before the contents of ``CMAKE_REQUIRED_FLAGS``. - - ``CMAKE_REQUIRED_DEFINITIONS`` - A :ref:`;-list <CMake Language Lists>` of compiler definitions of the form - ``-DFOO`` or ``-DFOO=bar``. A definition for the name specified by - ``<resultVar>`` will also be added automatically. - - ``CMAKE_REQUIRED_INCLUDES`` - A :ref:`;-list <CMake Language Lists>` of header search paths to pass to - the compiler. These will be the only header search paths used by - ``try_compile()``, i.e. the contents of the :prop_dir:`INCLUDE_DIRECTORIES` - directory property will be ignored. - - ``CMAKE_REQUIRED_LINK_OPTIONS`` - A :ref:`;-list <CMake Language Lists>` of options to add to the link - command (see :command:`try_compile` for further details). - - ``CMAKE_REQUIRED_LIBRARIES`` - A :ref:`;-list <CMake Language Lists>` of libraries to add to the link - command. These can be the name of system libraries or they can be - :ref:`Imported Targets <Imported Targets>` (see :command:`try_compile` for - further details). - - ``CMAKE_REQUIRED_QUIET`` - If this variable evaluates to a boolean true value, all status messages - associated with the check will be suppressed. - - The check is only performed once, with the result cached in the variable - named by ``<resultVar>``. Every subsequent CMake run will re-use this cached - value rather than performing the check again, even if the ``<code>`` changes. - In order to force the check to be re-evaluated, the variable named by + The check is only performed once, with the result cached in the variable named + by ``<resultVar>``. Every subsequent CMake run will re-use this cached value + rather than performing the check again, even if the ``<code>`` changes. In + order to force the check to be re-evaluated, the variable named by ``<resultVar>`` must be manually removed from the cache. + The compile and link commands can be influenced by setting any of the + following variables prior to calling ``check_objcxx_source_compiles()`` + +.. include:: /module/CMAKE_REQUIRED_FLAGS.txt + +.. include:: /module/CMAKE_REQUIRED_DEFINITIONS.txt + +.. include:: /module/CMAKE_REQUIRED_INCLUDES.txt + +.. include:: /module/CMAKE_REQUIRED_LINK_OPTIONS.txt + +.. include:: /module/CMAKE_REQUIRED_LIBRARIES.txt + +.. include:: /module/CMAKE_REQUIRED_QUIET.txt + #]=======================================================================] include_guard(GLOBAL) diff --git a/Modules/CheckOBJCXXSourceRuns.cmake b/Modules/CheckOBJCXXSourceRuns.cmake index 05a5e4c..b2831b6 100644 --- a/Modules/CheckOBJCXXSourceRuns.cmake +++ b/Modules/CheckOBJCXXSourceRuns.cmake @@ -23,47 +23,27 @@ subsequently be run. be set to 1, otherwise it will be set to an value that evaluates to boolean false (e.g. an empty string or an error message). - The underlying check is performed by the :command:`try_run` command. The - compile and link commands can be influenced by setting any of the following - variables prior to calling ``check_objcxx_source_runs()``: - - ``CMAKE_REQUIRED_FLAGS`` - Additional flags to pass to the compiler. Note that the contents of - :variable:`CMAKE_OBJCXX_FLAGS <CMAKE_<LANG>_FLAGS>` and its associated - configuration-specific variable are automatically added to the compiler - command before the contents of ``CMAKE_REQUIRED_FLAGS``. - - ``CMAKE_REQUIRED_DEFINITIONS`` - A :ref:`;-list <CMake Language Lists>` of compiler definitions of the form - ``-DFOO`` or ``-DFOO=bar``. A definition for the name specified by - ``<resultVar>`` will also be added automatically. - - ``CMAKE_REQUIRED_INCLUDES`` - A :ref:`;-list <CMake Language Lists>` of header search paths to pass to - the compiler. These will be the only header search paths used by - ``try_run()``, i.e. the contents of the :prop_dir:`INCLUDE_DIRECTORIES` - directory property will be ignored. - - ``CMAKE_REQUIRED_LINK_OPTIONS`` - A :ref:`;-list <CMake Language Lists>` of options to add to the link - command (see :command:`try_run` for further details). - - ``CMAKE_REQUIRED_LIBRARIES`` - A :ref:`;-list <CMake Language Lists>` of libraries to add to the link - command. These can be the name of system libraries or they can be - :ref:`Imported Targets <Imported Targets>` (see :command:`try_run` for - further details). - - ``CMAKE_REQUIRED_QUIET`` - If this variable evaluates to a boolean true value, all status messages - associated with the check will be suppressed. - - The check is only performed once, with the result cached in the variable - named by ``<resultVar>``. Every subsequent CMake run will re-use this cached - value rather than performing the check again, even if the ``<code>`` changes. - In order to force the check to be re-evaluated, the variable named by + The check is only performed once, with the result cached in the variable named + by ``<resultVar>``. Every subsequent CMake run will re-use this cached value + rather than performing the check again, even if the ``<code>`` changes. In + order to force the check to be re-evaluated, the variable named by ``<resultVar>`` must be manually removed from the cache. + The compile and link commands can be influenced by setting any of the + following variables prior to calling ``check_objcxx_source_runs()`` + +.. include:: /module/CMAKE_REQUIRED_FLAGS.txt + +.. include:: /module/CMAKE_REQUIRED_DEFINITIONS.txt + +.. include:: /module/CMAKE_REQUIRED_INCLUDES.txt + +.. include:: /module/CMAKE_REQUIRED_LINK_OPTIONS.txt + +.. include:: /module/CMAKE_REQUIRED_LIBRARIES.txt + +.. include:: /module/CMAKE_REQUIRED_QUIET.txt + #]=======================================================================] include_guard(GLOBAL) diff --git a/Modules/CheckPrototypeDefinition.cmake b/Modules/CheckPrototypeDefinition.cmake index 3d53b93..c1a7a1c 100644 --- a/Modules/CheckPrototypeDefinition.cmake +++ b/Modules/CheckPrototypeDefinition.cmake @@ -35,20 +35,18 @@ Check if the prototype we expect is correct. The following variables may be set before calling this function to modify the way the check is run: -``CMAKE_REQUIRED_FLAGS`` - string of compile command line flags. -``CMAKE_REQUIRED_DEFINITIONS`` - list of macros to define (-DFOO=bar). -``CMAKE_REQUIRED_INCLUDES`` - list of include directories. -``CMAKE_REQUIRED_LINK_OPTIONS`` - .. versionadded:: 3.14 - list of options to pass to link command. -``CMAKE_REQUIRED_LIBRARIES`` - list of libraries to link. -``CMAKE_REQUIRED_QUIET`` - .. versionadded:: 3.1 - execute quietly without messages. +.. include:: /module/CMAKE_REQUIRED_FLAGS.txt + +.. include:: /module/CMAKE_REQUIRED_DEFINITIONS.txt + +.. include:: /module/CMAKE_REQUIRED_INCLUDES.txt + +.. include:: /module/CMAKE_REQUIRED_LINK_OPTIONS.txt + +.. include:: /module/CMAKE_REQUIRED_LIBRARIES.txt + +.. include:: /module/CMAKE_REQUIRED_QUIET.txt + #]=======================================================================] # diff --git a/Modules/CheckSourceCompiles.cmake b/Modules/CheckSourceCompiles.cmake index 9788798..041b59c 100644 --- a/Modules/CheckSourceCompiles.cmake +++ b/Modules/CheckSourceCompiles.cmake @@ -47,47 +47,27 @@ Check if given source compiles and links into an executable. end program" HAVE_ERROR_STOP) - The underlying check is performed by the :command:`try_compile` command. The - compile and link commands can be influenced by setting any of the following - variables prior to calling ``check_source_compiles()``: - - ``CMAKE_REQUIRED_FLAGS`` - Additional flags to pass to the compiler. Note that the contents of - :variable:`CMAKE_<LANG>_FLAGS <CMAKE_<LANG>_FLAGS>` and its associated - configuration-specific variable are automatically added to the compiler - command before the contents of ``CMAKE_REQUIRED_FLAGS``. - - ``CMAKE_REQUIRED_DEFINITIONS`` - A :ref:`;-list <CMake Language Lists>` of compiler definitions of the form - ``-DFOO`` or ``-DFOO=bar``. A definition for the name specified by - ``<resultVar>`` will also be added automatically. - - ``CMAKE_REQUIRED_INCLUDES`` - A :ref:`;-list <CMake Language Lists>` of header search paths to pass to - the compiler. These will be the only header search paths used by - ``try_compile()``, i.e. the contents of the :prop_dir:`INCLUDE_DIRECTORIES` - directory property will be ignored. - - ``CMAKE_REQUIRED_LINK_OPTIONS`` - A :ref:`;-list <CMake Language Lists>` of options to add to the link - command (see :command:`try_compile` for further details). - - ``CMAKE_REQUIRED_LIBRARIES`` - A :ref:`;-list <CMake Language Lists>` of libraries to add to the link - command. These can be the name of system libraries or they can be - :ref:`Imported Targets <Imported Targets>` (see :command:`try_compile` for - further details). - - ``CMAKE_REQUIRED_QUIET`` - If this variable evaluates to a boolean true value, all status messages - associated with the check will be suppressed. - The check is only performed once, with the result cached in the variable named by ``<resultVar>``. Every subsequent CMake run will re-use this cached value rather than performing the check again, even if the ``<code>`` changes. In order to force the check to be re-evaluated, the variable named by ``<resultVar>`` must be manually removed from the cache. + The compile and link commands can be influenced by setting any of the + following variables prior to calling ``check_source_compiles()``: + +.. include:: /module/CMAKE_REQUIRED_FLAGS.txt + +.. include:: /module/CMAKE_REQUIRED_DEFINITIONS.txt + +.. include:: /module/CMAKE_REQUIRED_INCLUDES.txt + +.. include:: /module/CMAKE_REQUIRED_LINK_OPTIONS.txt + +.. include:: /module/CMAKE_REQUIRED_LIBRARIES.txt + +.. include:: /module/CMAKE_REQUIRED_QUIET.txt + #]=======================================================================] include_guard(GLOBAL) diff --git a/Modules/CheckSourceRuns.cmake b/Modules/CheckSourceRuns.cmake index e2fa579..822ee07 100644 --- a/Modules/CheckSourceRuns.cmake +++ b/Modules/CheckSourceRuns.cmake @@ -47,47 +47,27 @@ subsequently be run. end program" HAVE_COARRAY) - The underlying check is performed by the :command:`try_run` command. The - compile and link commands can be influenced by setting any of the following - variables prior to calling ``check_source_runs()``: - - ``CMAKE_REQUIRED_FLAGS`` - Additional flags to pass to the compiler. Note that the contents of - :variable:`CMAKE_<LANG>_FLAGS <CMAKE_<LANG>_FLAGS>` and its associated - configuration-specific variable are automatically added to the compiler - command before the contents of ``CMAKE_REQUIRED_FLAGS``. - - ``CMAKE_REQUIRED_DEFINITIONS`` - A :ref:`;-list <CMake Language Lists>` of compiler definitions of the form - ``-DFOO`` or ``-DFOO=bar``. A definition for the name specified by - ``<resultVar>`` will also be added automatically. - - ``CMAKE_REQUIRED_INCLUDES`` - A :ref:`;-list <CMake Language Lists>` of header search paths to pass to - the compiler. These will be the only header search paths used by - ``try_run()``, i.e. the contents of the :prop_dir:`INCLUDE_DIRECTORIES` - directory property will be ignored. - - ``CMAKE_REQUIRED_LINK_OPTIONS`` - A :ref:`;-list <CMake Language Lists>` of options to add to the link - command (see :command:`try_run` for further details). - - ``CMAKE_REQUIRED_LIBRARIES`` - A :ref:`;-list <CMake Language Lists>` of libraries to add to the link - command. These can be the name of system libraries or they can be - :ref:`Imported Targets <Imported Targets>` (see :command:`try_run` for - further details). - - ``CMAKE_REQUIRED_QUIET`` - If this variable evaluates to a boolean true value, all status messages - associated with the check will be suppressed. - - The check is only performed once, with the result cached in the variable - named by ``<resultVar>``. Every subsequent CMake run will re-use this cached - value rather than performing the check again, even if the ``<code>`` changes. - In order to force the check to be re-evaluated, the variable named by + The check is only performed once, with the result cached in the variable named + by ``<resultVar>``. Every subsequent CMake run will re-use this cached value + rather than performing the check again, even if the ``<code>`` changes. In + order to force the check to be re-evaluated, the variable named by ``<resultVar>`` must be manually removed from the cache. + The compile and link commands can be influenced by setting any of the + following variables prior to calling ``check_source_runs()`` + +.. include:: /module/CMAKE_REQUIRED_FLAGS.txt + +.. include:: /module/CMAKE_REQUIRED_DEFINITIONS.txt + +.. include:: /module/CMAKE_REQUIRED_INCLUDES.txt + +.. include:: /module/CMAKE_REQUIRED_LINK_OPTIONS.txt + +.. include:: /module/CMAKE_REQUIRED_LIBRARIES.txt + +.. include:: /module/CMAKE_REQUIRED_QUIET.txt + #]=======================================================================] include_guard(GLOBAL) diff --git a/Modules/CheckStructHasMember.cmake b/Modules/CheckStructHasMember.cmake index 8217c84..81ea9fd 100644 --- a/Modules/CheckStructHasMember.cmake +++ b/Modules/CheckStructHasMember.cmake @@ -26,20 +26,17 @@ Check if the given struct or class has the specified member variable The following variables may be set before calling this macro to modify the way the check is run: -``CMAKE_REQUIRED_FLAGS`` - string of compile command line flags. -``CMAKE_REQUIRED_DEFINITIONS`` - list of macros to define (-DFOO=bar). -``CMAKE_REQUIRED_INCLUDES`` - list of include directories. -``CMAKE_REQUIRED_LINK_OPTIONS`` - .. versionadded:: 3.14 - list of options to pass to link command. -``CMAKE_REQUIRED_LIBRARIES`` - list of libraries to link. -``CMAKE_REQUIRED_QUIET`` - .. versionadded:: 3.1 - execute quietly without messages. +.. include:: /module/CMAKE_REQUIRED_FLAGS.txt + +.. include:: /module/CMAKE_REQUIRED_DEFINITIONS.txt + +.. include:: /module/CMAKE_REQUIRED_INCLUDES.txt + +.. include:: /module/CMAKE_REQUIRED_LINK_OPTIONS.txt + +.. include:: /module/CMAKE_REQUIRED_LIBRARIES.txt + +.. include:: /module/CMAKE_REQUIRED_QUIET.txt Example: @@ -51,8 +48,7 @@ Example: #]=======================================================================] include_guard(GLOBAL) -include(CheckCSourceCompiles) -include(CheckCXXSourceCompiles) +include(CheckSourceCompiles) macro (CHECK_STRUCT_HAS_MEMBER _STRUCT _MEMBER _HEADER _RESULT) set(_INCLUDE_FILES) @@ -78,9 +74,9 @@ int main() ") if("${_lang}" STREQUAL "C") - CHECK_C_SOURCE_COMPILES("${_CHECK_STRUCT_MEMBER_SOURCE_CODE}" ${_RESULT}) + CHECK_SOURCE_COMPILES(C "${_CHECK_STRUCT_MEMBER_SOURCE_CODE}" ${_RESULT}) elseif("${_lang}" STREQUAL "CXX") - CHECK_CXX_SOURCE_COMPILES("${_CHECK_STRUCT_MEMBER_SOURCE_CODE}" ${_RESULT}) + CHECK_SOURCE_COMPILES(CXX "${_CHECK_STRUCT_MEMBER_SOURCE_CODE}" ${_RESULT}) else() message(FATAL_ERROR "Unknown language:\n ${_lang}\nSupported languages: C, CXX.\n") endif() diff --git a/Modules/CheckSymbolExists.cmake b/Modules/CheckSymbolExists.cmake index c4a1574..931ed4a 100644 --- a/Modules/CheckSymbolExists.cmake +++ b/Modules/CheckSymbolExists.cmake @@ -31,22 +31,17 @@ If the check needs to be done in C++, consider using The following variables may be set before calling this macro to modify the way the check is run: -``CMAKE_REQUIRED_FLAGS`` - string of compile command line flags. -``CMAKE_REQUIRED_DEFINITIONS`` - a :ref:`;-list <CMake Language Lists>` of macros to define (-DFOO=bar). -``CMAKE_REQUIRED_INCLUDES`` - a :ref:`;-list <CMake Language Lists>` of header search paths to pass to - the compiler. -``CMAKE_REQUIRED_LINK_OPTIONS`` - .. versionadded:: 3.14 - a :ref:`;-list <CMake Language Lists>` of options to add to the link command. -``CMAKE_REQUIRED_LIBRARIES`` - a :ref:`;-list <CMake Language Lists>` of libraries to add to the link - command. See policy :policy:`CMP0075`. -``CMAKE_REQUIRED_QUIET`` - .. versionadded:: 3.1 - execute quietly without messages. +.. include:: /module/CMAKE_REQUIRED_FLAGS.txt + +.. include:: /module/CMAKE_REQUIRED_DEFINITIONS.txt + +.. include:: /module/CMAKE_REQUIRED_INCLUDES.txt + +.. include:: /module/CMAKE_REQUIRED_LINK_OPTIONS.txt + +.. include:: /module/CMAKE_REQUIRED_LIBRARIES.txt + +.. include:: /module/CMAKE_REQUIRED_QUIET.txt For example: @@ -62,7 +57,7 @@ For example: include_guard(GLOBAL) -cmake_policy(PUSH) +block(SCOPE_FOR POLICIES) cmake_policy(SET CMP0054 NEW) # if() quoted variables not dereferenced macro(CHECK_SYMBOL_EXISTS SYMBOL FILES VARIABLE) @@ -166,4 +161,4 @@ int main(int argc, char** argv) endif() endmacro() -cmake_policy(POP) +endblock() diff --git a/Modules/CheckTypeSize.cmake b/Modules/CheckTypeSize.cmake index 579d189..01ce1d2 100644 --- a/Modules/CheckTypeSize.cmake +++ b/Modules/CheckTypeSize.cmake @@ -67,20 +67,18 @@ member you can do something like this: The following variables may be set before calling this macro to modify the way the check is run: -``CMAKE_REQUIRED_FLAGS`` - string of compile command line flags. -``CMAKE_REQUIRED_DEFINITIONS`` - list of macros to define (-DFOO=bar). -``CMAKE_REQUIRED_INCLUDES`` - list of include directories. -``CMAKE_REQUIRED_LINK_OPTIONS`` - .. versionadded:: 3.14 - list of options to pass to link command. -``CMAKE_REQUIRED_LIBRARIES`` - list of libraries to link. -``CMAKE_REQUIRED_QUIET`` - .. versionadded:: 3.1 - execute quietly without messages. +.. include:: /module/CMAKE_REQUIRED_FLAGS.txt + +.. include:: /module/CMAKE_REQUIRED_DEFINITIONS.txt + +.. include:: /module/CMAKE_REQUIRED_INCLUDES.txt + +.. include:: /module/CMAKE_REQUIRED_LINK_OPTIONS.txt + +.. include:: /module/CMAKE_REQUIRED_LIBRARIES.txt + +.. include:: /module/CMAKE_REQUIRED_QUIET.txt + ``CMAKE_EXTRA_INCLUDE_FILES`` list of extra headers to include. #]=======================================================================] @@ -92,7 +90,7 @@ get_filename_component(__check_type_size_dir "${CMAKE_CURRENT_LIST_FILE}" PATH) include_guard(GLOBAL) -cmake_policy(PUSH) +block(SCOPE_FOR POLICIES) cmake_policy(SET CMP0054 NEW) #----------------------------------------------------------------------------- @@ -294,4 +292,4 @@ macro(CHECK_TYPE_SIZE TYPE VARIABLE) endmacro() #----------------------------------------------------------------------------- -cmake_policy(POP) +endblock() diff --git a/Modules/CheckVariableExists.cmake b/Modules/CheckVariableExists.cmake index 3a7a431..9e5d710 100644 --- a/Modules/CheckVariableExists.cmake +++ b/Modules/CheckVariableExists.cmake @@ -26,18 +26,16 @@ Check if the variable exists. The following variables may be set before calling this macro to modify the way the check is run: -``CMAKE_REQUIRED_FLAGS`` - string of compile command line flags. -``CMAKE_REQUIRED_DEFINITIONS`` - list of macros to define (-DFOO=bar). -``CMAKE_REQUIRED_LINK_OPTIONS`` - .. versionadded:: 3.14 - list of options to pass to link command. -``CMAKE_REQUIRED_LIBRARIES`` - list of libraries to link. -``CMAKE_REQUIRED_QUIET`` - .. versionadded:: 3.1 - execute quietly without messages. +.. include:: /module/CMAKE_REQUIRED_FLAGS.txt + +.. include:: /module/CMAKE_REQUIRED_DEFINITIONS.txt + +.. include:: /module/CMAKE_REQUIRED_LINK_OPTIONS.txt + +.. include:: /module/CMAKE_REQUIRED_LIBRARIES.txt + +.. include:: /module/CMAKE_REQUIRED_QUIET.txt + #]=======================================================================] include_guard(GLOBAL) diff --git a/Modules/Compiler/Clang-CXX.cmake b/Modules/Compiler/Clang-CXX.cmake index 33154fd..a74e90b 100644 --- a/Modules/Compiler/Clang-CXX.cmake +++ b/Modules/Compiler/Clang-CXX.cmake @@ -30,16 +30,18 @@ if("x${CMAKE_CXX_COMPILER_FRONTEND_VARIANT}" STREQUAL "xMSVC") endif() endif() -if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 16.0) - string(CONCAT CMAKE_EXPERIMENTAL_CXX_SCANDEP_SOURCE - "${CMAKE_CXX_COMPILER_CLANG_SCAN_DEPS}" - " -format=p1689" - " --" - " <CMAKE_CXX_COMPILER> <DEFINES> <INCLUDES> <FLAGS>" - " -x c++ <SOURCE> -c -o <OBJECT>" - " -MT <DYNDEP_FILE>" - " -MD -MF <DEP_FILE>" - " > <DYNDEP_FILE>") - set(CMAKE_EXPERIMENTAL_CXX_MODULE_MAP_FORMAT "clang") - set(CMAKE_EXPERIMENTAL_CXX_MODULE_MAP_FLAG "@<MODULE_MAP_FILE>") -endif () +if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 16.0) + if("x${CMAKE_CXX_COMPILER_FRONTEND_VARIANT}" STREQUAL "xGNU") + string(CONCAT CMAKE_EXPERIMENTAL_CXX_SCANDEP_SOURCE + "\"${CMAKE_CXX_COMPILER_CLANG_SCAN_DEPS}\"" + " -format=p1689" + " --" + " <CMAKE_CXX_COMPILER> <DEFINES> <INCLUDES> <FLAGS>" + " -x c++ <SOURCE> -c -o <OBJECT>" + " -MT <DYNDEP_FILE>" + " -MD -MF <DEP_FILE>" + " > <DYNDEP_FILE>") + set(CMAKE_EXPERIMENTAL_CXX_MODULE_MAP_FORMAT "clang") + set(CMAKE_EXPERIMENTAL_CXX_MODULE_MAP_FLAG "@<MODULE_MAP_FILE>") + endif() +endif() diff --git a/Modules/Compiler/IAR-ASM.cmake b/Modules/Compiler/IAR-ASM.cmake index bae0fbd..4c0025c 100644 --- a/Modules/Compiler/IAR-ASM.cmake +++ b/Modules/Compiler/IAR-ASM.cmake @@ -2,44 +2,74 @@ include(Compiler/IAR) -cmake_policy(PUSH) -cmake_policy(SET CMP0057 NEW) # if IN_LIST - -set(_CMAKE_IAR_ITOOLS "ARM" "RH850" "RL78" "RX" "RISC-V" "STM8") -set(_CMAKE_IAR_XTOOLS "AVR" "MSP430" "V850" "8051") +# Architecture specific +if("${CMAKE_ASM${ASM_DIALECT}_COMPILER_ARCHITECTURE_ID}" STREQUAL "ARM") + __compiler_iar_ilink(ASM) + __assembler_iar_deps("-y" 9.30) + set(_CMAKE_IAR_SILENCER_FLAG " -S") + set(CMAKE_ASM_SOURCE_FILE_EXTENSIONS s;asm;msa;S) -set(_CMAKE_IAR_ASM_SILENT "RH850" "RL78" "RX" "RISC-V" "STM8") -if("${CMAKE_ASM${ASM_DIALECT}_COMPILER_ARCHITECTURE_ID}" IN_LIST _CMAKE_IAR_ASM_SILENT) +elseif("${CMAKE_ASM${ASM_DIALECT}_COMPILER_ARCHITECTURE_ID}" STREQUAL "RX") + __compiler_iar_ilink(ASM) + __assembler_iar_deps("--dependencies=ns" 2.50.1) set(_CMAKE_IAR_SILENCER_FLAG " --silent") -else() - set(_CMAKE_IAR_SILENCER_FLAG " -S") -endif() + set(CMAKE_ASM_SOURCE_FILE_EXTENSIONS s;asm;msa;S) -string(APPEND CMAKE_ASM_FLAGS_INIT " ") -string(APPEND CMAKE_ASM_FLAGS_DEBUG_INIT " -r") -string(APPEND CMAKE_ASM_FLAGS_MINSIZEREL_INIT " -DNDEBUG") -string(APPEND CMAKE_ASM_FLAGS_RELEASE_INIT " -DNDEBUG") -string(APPEND CMAKE_ASM_FLAGS_RELWITHDEBINFO_INIT " -r -DNDEBUG") +elseif("${CMAKE_ASM${ASM_DIALECT}_COMPILER_ARCHITECTURE_ID}" STREQUAL "RH850") + __compiler_iar_ilink(ASM) + __assembler_iar_deps("--dependencies=ns" 2) + set(_CMAKE_IAR_SILENCER_FLAG " --silent") + set(CMAKE_ASM_SOURCE_FILE_EXTENSIONS s;asm;msa;S) -set(CMAKE_ASM_COMPILE_OBJECT "<CMAKE_ASM_COMPILER> ${_CMAKE_IAR_SILENCER_FLAG} <SOURCE> <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT>") +elseif("${CMAKE_ASM${ASM_DIALECT}_COMPILER_ARCHITECTURE_ID}" STREQUAL "RL78") + __compiler_iar_ilink(ASM) + __assembler_iar_deps("--dependencies=ns" 2) + set(_CMAKE_IAR_SILENCER_FLAG " --silent") + set(CMAKE_ASM_SOURCE_FILE_EXTENSIONS s;asm;msa;S) -if("${CMAKE_ASM${ASM_DIALECT}_COMPILER_ARCHITECTURE_ID}" IN_LIST _CMAKE_IAR_ITOOLS) +elseif("${CMAKE_ASM${ASM_DIALECT}_COMPILER_ARCHITECTURE_ID}" MATCHES "(RISCV|RISC-V)") __compiler_iar_ilink(ASM) + __assembler_iar_deps("--dependencies=ns" 1) + set(_CMAKE_IAR_SILENCER_FLAG " --silent") set(CMAKE_ASM_SOURCE_FILE_EXTENSIONS s;asm;msa;S) -elseif("${CMAKE_ASM${ASM_DIALECT}_COMPILER_ARCHITECTURE_ID}" IN_LIST _CMAKE_IAR_XTOOLS) +elseif("${CMAKE_ASM${ASM_DIALECT}_COMPILER_ARCHITECTURE_ID}" STREQUAL "AVR") + __compiler_iar_xlink(ASM) + __assembler_iar_deps("-y" 8) + set(_CMAKE_IAR_SILENCER_FLAG " -S") + set(CMAKE_ASM_SOURCE_FILE_EXTENSIONS s90;asm;msa) + +elseif("${CMAKE_ASM${ASM_DIALECT}_COMPILER_ARCHITECTURE_ID}" STREQUAL "MSP430") __compiler_iar_xlink(ASM) - # AVR=s90, MSP430=s43, V850=s85, 8051=s51 - set(CMAKE_ASM_SOURCE_FILE_EXTENSIONS s90;s43;s85;s51;asm;msa) + __assembler_iar_deps("-y" 8) + set(_CMAKE_IAR_SILENCER_FLAG " -S") + set(CMAKE_ASM_SOURCE_FILE_EXTENSIONS s43;asm;msa) -else() - message(FATAL_ERROR "CMAKE_ASM${ASM_DIALECT}_COMPILER_ARCHITECTURE_ID not detected. This should be automatic.") +elseif("${CMAKE_ASM${ASM_DIALECT}_COMPILER_ARCHITECTURE_ID}" STREQUAL "V850") + __compiler_iar_xlink(ASM) + set(_CMAKE_IAR_SILENCER_FLAG " -S") + set(CMAKE_ASM_SOURCE_FILE_EXTENSIONS s85;asm;msa) + +elseif("${CMAKE_ASM${ASM_DIALECT}_COMPILER_ARCHITECTURE_ID}" STREQUAL "8051") + __compiler_iar_xlink(ASM) + set(_CMAKE_IAR_SILENCER_FLAG " -S") + set(CMAKE_ASM_SOURCE_FILE_EXTENSIONS s51;asm;msa) + +elseif("${CMAKE_ASM${ASM_DIALECT}_COMPILER_ARCHITECTURE_ID}" STREQUAL "STM8") + __compiler_iar_ilink(ASM) + __assembler_iar_deps("--dependencies=ns" 2) + set(_CMAKE_IAR_SILENCER_FLAG " --silent") + set(CMAKE_ASM_SOURCE_FILE_EXTENSIONS s;asm;msa;S) +else() + message(FATAL_ERROR "CMAKE_ASM${ASM_DIALECT}_COMPILER_ARCHITECTURE_ID not detected. This should be automatic." ) endif() -unset(_CMAKE_IAR_ITOOLS) -unset(_CMAKE_IAR_XTOOLS) -unset(_CMAKE_IAR_ASM_SILENT) -unset(_CMAKE_IAR_SILENCER_FLAG) +string(APPEND CMAKE_ASM_FLAGS_DEBUG_INIT " -r") +string(APPEND CMAKE_ASM_FLAGS_MINSIZEREL_INIT " -DNDEBUG") +string(APPEND CMAKE_ASM_FLAGS_RELEASE_INIT " -DNDEBUG") +string(APPEND CMAKE_ASM_FLAGS_RELWITHDEBINFO_INIT " -r -DNDEBUG") -cmake_policy(POP) +set(CMAKE_ASM_COMPILE_OBJECT "<CMAKE_ASM_COMPILER> ${_CMAKE_IAR_SILENCER_FLAG} <SOURCE> <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT>") + +unset(_CMAKE_IAR_SILENCER_FLAG) diff --git a/Modules/Compiler/IAR.cmake b/Modules/Compiler/IAR.cmake index e75df59..0aca283 100644 --- a/Modules/Compiler/IAR.cmake +++ b/Modules/Compiler/IAR.cmake @@ -53,3 +53,9 @@ macro(__compiler_iar_xlink lang) set(CMAKE_LIBRARY_PATH_FLAG "-I") endmacro() + +macro(__assembler_iar_deps flag min_version) + if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL ${min_version}) + set(CMAKE_DEPFILE_FLAGS_ASM "${flag} <DEP_FILE>") + endif() +endmacro() diff --git a/Modules/Compiler/IBMClang.cmake b/Modules/Compiler/IBMClang.cmake index a9d760f..169a0f0 100644 --- a/Modules/Compiler/IBMClang.cmake +++ b/Modules/Compiler/IBMClang.cmake @@ -43,7 +43,10 @@ macro(__compiler_ibmclang lang) set(_CMAKE_${lang}_IPO_SUPPORTED_BY_CMAKE YES) set(_CMAKE_${lang}_IPO_MAY_BE_SUPPORTED_BY_COMPILER YES) - set(_CMAKE_LTO_THIN TRUE) + # Thin LTO is not yet supported on AIX. + if(NOT (CMAKE_SYSTEM_NAME STREQUAL "AIX")) + set(_CMAKE_LTO_THIN TRUE) + endif() if(_CMAKE_LTO_THIN) set(CMAKE_${lang}_COMPILE_OPTIONS_IPO "-flto=thin") diff --git a/Modules/Compiler/NVIDIA-CUDA.cmake b/Modules/Compiler/NVIDIA-CUDA.cmake index 0823954..c839d1c 100644 --- a/Modules/Compiler/NVIDIA-CUDA.cmake +++ b/Modules/Compiler/NVIDIA-CUDA.cmake @@ -8,6 +8,11 @@ set(_CMAKE_COMPILE_AS_CUDA_FLAG "-x cu") set(_CMAKE_CUDA_WHOLE_FLAG "-c") set(_CMAKE_CUDA_RDC_FLAG "-rdc=true") set(_CMAKE_CUDA_PTX_FLAG "-ptx") +set(_CMAKE_CUDA_CUBIN_FLAG "-cubin") +set(_CMAKE_CUDA_FATBIN_FLAG "-fatbin") +if(CMAKE_CUDA_COMPILER_VERSION VERSION_GREATER_EQUAL "11.7.0") + set(_CMAKE_CUDA_OPTIX_FLAG "-optix-ir") +endif() if (CMAKE_CUDA_COMPILER_VERSION VERSION_GREATER_EQUAL 10.2.89) # The -forward-unknown-to-host-compiler flag was only diff --git a/Modules/FindCUDA.cmake b/Modules/FindCUDA.cmake index c928157..220b9ab 100644 --- a/Modules/FindCUDA.cmake +++ b/Modules/FindCUDA.cmake @@ -2,7 +2,12 @@ FindCUDA -------- -.. warning:: *Deprecated since version 3.10.* +.. versionchanged:: 3.27 + This module is available only if policy :policy:`CMP0146` is not set to ``NEW``. + Port projects to CMake's first-class ``CUDA`` language support. + +.. deprecated:: 3.10 + Do not use this module in new code. It is no longer necessary to use this module or call ``find_package(CUDA)`` for compiling CUDA code. Instead, list ``CUDA`` among the languages named @@ -555,6 +560,23 @@ The script defines the following variables: # ############################################################################### +cmake_policy(GET CMP0146 _FindCUDA_CMP0146) +if(_FindCUDA_CMP0146 STREQUAL "NEW") + message(FATAL_ERROR "The FindCUDA module has been removed by policy CMP0146.") +endif() + +if(CMAKE_GENERATOR MATCHES "Visual Studio") + cmake_policy(GET CMP0147 _FindCUDA_CMP0147) + if(_FindCUDA_CMP0147 STREQUAL "NEW") + message(FATAL_ERROR "The FindCUDA module does not work in Visual Studio with policy CMP0147.") + endif() +endif() + +if(_FindCUDA_testing) + set(_FindCUDA_included TRUE) + return() +endif() + # FindCUDA.cmake # This macro helps us find the location of helper files we will need the full path to @@ -1052,6 +1074,7 @@ if(CUDA_USE_STATIC_CUDA_RUNTIME) if(NOT APPLE AND NOT (CMAKE_SYSTEM_NAME STREQUAL "QNX")) #On Linux, you must link against librt when using the static cuda runtime. find_library(CUDA_rt_LIBRARY rt) + mark_as_advanced(CUDA_rt_LIBRARY) if (NOT CUDA_rt_LIBRARY) message(WARNING "Expecting to find librt for libcudart_static, but didn't find it.") endif() diff --git a/Modules/FindCUDAToolkit.cmake b/Modules/FindCUDAToolkit.cmake index d7c6d5e..67bf424 100644 --- a/Modules/FindCUDAToolkit.cmake +++ b/Modules/FindCUDAToolkit.cmake @@ -109,6 +109,7 @@ of the following libraries that are part of the CUDAToolkit: - :ref:`CUDA Runtime Library<cuda_toolkit_rt_lib>` - :ref:`CUDA Driver Library<cuda_toolkit_driver_lib>` - :ref:`cuBLAS<cuda_toolkit_cuBLAS>` +- :ref:`cuDLA<cuda_toolkit_cuDLA>` - :ref:`cuFile<cuda_toolkit_cuFile>` - :ref:`cuFFT<cuda_toolkit_cuFFT>` - :ref:`cuRAND<cuda_toolkit_cuRAND>` @@ -166,6 +167,19 @@ Targets Created: - ``CUDA::cublasLt`` starting in CUDA 10.1 - ``CUDA::cublasLt_static`` starting in CUDA 10.1 +.. _`cuda_toolkit_cuDLA`: + +cuDLA +"""""" + +.. versionadded:: 3.27 + +The NVIDIA Tegra Deep Learning Accelerator `cuDLA <https://docs.nvidia.com/cuda/cublas/index.html>`_ library. + +Targets Created: + +- ``CUDA::cudla`` starting in CUDA 11.6 + .. _`cuda_toolkit_cuFile`: cuFile @@ -609,8 +623,8 @@ else() endif() unset(_CUDA_NVCC_OUT) - mark_as_advanced(CUDAToolkit_BIN_DIR) set(CUDAToolkit_BIN_DIR "${CUDAToolkit_BIN_DIR}" CACHE PATH "" FORCE) + mark_as_advanced(CUDAToolkit_BIN_DIR) endif() if(CUDAToolkit_SENTINEL_FILE) @@ -1046,6 +1060,11 @@ if(CUDAToolkit_FOUND) _CUDAToolkit_find_and_add_import_lib(cuFile_rdma_static DEPS cuFile_static culibos) endif() + if(CUDAToolkit_VERSION VERSION_GREATER_EQUAL 11.6) + _CUDAToolkit_find_and_add_import_lib(cudla) + endif() + + # cuFFTW depends on cuFFT _CUDAToolkit_find_and_add_import_lib(cufftw DEPS cufft) _CUDAToolkit_find_and_add_import_lib(cufftw_static DEPS cufft_static) @@ -1089,6 +1108,7 @@ if(CUDAToolkit_FOUND) "${CUDAToolkit_INCLUDE_DIR}/../extras/CUPTI/include" "${CUDAToolkit_INCLUDE_DIR}" NO_DEFAULT_PATH) + mark_as_advanced(CUDAToolkit_CUPTI_INCLUDE_DIR) if(CUDAToolkit_CUPTI_INCLUDE_DIR) _CUDAToolkit_find_and_add_import_lib(cupti diff --git a/Modules/FindHDF5.cmake b/Modules/FindHDF5.cmake index 62c492c..a44c6f9 100644 --- a/Modules/FindHDF5.cmake +++ b/Modules/FindHDF5.cmake @@ -217,16 +217,9 @@ endif() # Test first if the current compilers automatically wrap HDF5 function(_HDF5_test_regular_compiler_C success version is_parallel) - set(scratch_directory - ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/hdf5) if(NOT ${success} OR - NOT EXISTS ${scratch_directory}/compiler_has_h5_c) - set(test_file ${scratch_directory}/cmake_hdf5_test.c) - # CXX project without C enabled - if(CMAKE_CXX_COMPILER_LOADED AND NOT CMAKE_C_COMPILER_LOADED) - set(test_file ${scratch_directory}/cmake_hdf5_test.cpp) - endif() - file(WRITE ${test_file} + NOT EXISTS ${_HDF5_TEST_DIR}/compiler_has_h5_c) + file(WRITE "${_HDF5_TEST_DIR}/${_HDF5_TEST_SRC}" "#include <hdf5.h>\n" "const char* info_ver = \"INFO\" \":\" H5_VERSION;\n" "#ifdef H5_HAVE_PARALLEL\n" @@ -242,12 +235,12 @@ function(_HDF5_test_regular_compiler_C success version is_parallel) " fid = H5Fcreate(\"foo.h5\",H5F_ACC_TRUNC,H5P_DEFAULT,H5P_DEFAULT);\n" " return 0;\n" "}") - try_compile(${success} SOURCES ${test_file} - COPY_FILE ${scratch_directory}/compiler_has_h5_c + try_compile(${success} SOURCES "${_HDF5_TEST_DIR}/${_HDF5_TEST_SRC}" + COPY_FILE ${_HDF5_TEST_DIR}/compiler_has_h5_c ) endif() - if(${success} AND EXISTS ${scratch_directory}/compiler_has_h5_c) - file(STRINGS ${scratch_directory}/compiler_has_h5_c INFO_STRINGS + if(${success} AND EXISTS ${_HDF5_TEST_DIR}/compiler_has_h5_c) + file(STRINGS ${_HDF5_TEST_DIR}/compiler_has_h5_c INFO_STRINGS REGEX "^INFO:" ) string(REGEX MATCH "^INFO:([0-9]+\\.[0-9]+\\.[0-9]+)(-patch([0-9]+))?" @@ -268,11 +261,9 @@ function(_HDF5_test_regular_compiler_C success version is_parallel) endfunction() function(_HDF5_test_regular_compiler_CXX success version is_parallel) - set(scratch_directory ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/hdf5) if(NOT ${success} OR - NOT EXISTS ${scratch_directory}/compiler_has_h5_cxx) - set(test_file ${scratch_directory}/cmake_hdf5_test.cxx) - file(WRITE ${test_file} + NOT EXISTS ${_HDF5_TEST_DIR}/compiler_has_h5_cxx) + file(WRITE "${_HDF5_TEST_DIR}/${_HDF5_TEST_SRC}" "#include <H5Cpp.h>\n" "#ifndef H5_NO_NAMESPACE\n" "using namespace H5;\n" @@ -290,12 +281,12 @@ function(_HDF5_test_regular_compiler_CXX success version is_parallel) " H5File file(\"foo.h5\", H5F_ACC_TRUNC);\n" " return 0;\n" "}") - try_compile(${success} SOURCES ${test_file} - COPY_FILE ${scratch_directory}/compiler_has_h5_cxx + try_compile(${success} SOURCES "${_HDF5_TEST_DIR}/${_HDF5_TEST_SRC}" + COPY_FILE ${_HDF5_TEST_DIR}/compiler_has_h5_cxx ) endif() - if(${success} AND EXISTS ${scratch_directory}/compiler_has_h5_cxx) - file(STRINGS ${scratch_directory}/compiler_has_h5_cxx INFO_STRINGS + if(${success} AND EXISTS ${_HDF5_TEST_DIR}/compiler_has_h5_cxx) + file(STRINGS ${_HDF5_TEST_DIR}/compiler_has_h5_cxx INFO_STRINGS REGEX "^INFO:" ) string(REGEX MATCH "^INFO:([0-9]+\\.[0-9]+\\.[0-9]+)(-patch([0-9]+))?" @@ -317,17 +308,14 @@ endfunction() function(_HDF5_test_regular_compiler_Fortran success is_parallel) if(NOT ${success}) - set(scratch_directory - ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/hdf5) - set(test_file ${scratch_directory}/cmake_hdf5_test.f90) - file(WRITE ${test_file} + file(WRITE "${_HDF5_TEST_DIR}/${_HDF5_TEST_SRC}" "program hdf5_hello\n" " use hdf5\n" " integer error\n" " call h5open_f(error)\n" " call h5close_f(error)\n" "end\n") - try_compile(${success} SOURCES ${test_file}) + try_compile(${success} SOURCES "${_HDF5_TEST_DIR}/${_HDF5_TEST_SRC}") if(${success}) execute_process(COMMAND ${CMAKE_Fortran_COMPILER} -showconfig OUTPUT_VARIABLE config_output @@ -359,38 +347,38 @@ function( _HDF5_invoke_compiler language output_var return_value_var version_var else() set(lib_type_args -shlib) endif() - set(scratch_dir ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/hdf5) - if("${language}" STREQUAL "C") - set(test_file ${scratch_dir}/cmake_hdf5_test.c) - elseif("${language}" STREQUAL "CXX") - set(test_file ${scratch_dir}/cmake_hdf5_test.cxx) - elseif("${language}" STREQUAL "Fortran") - set(test_file ${scratch_dir}/cmake_hdf5_test.f90) - endif() # Verify that the compiler wrapper can actually compile: sometimes the compiler # wrapper exists, but not the compiler. E.g. Miniconda / Anaconda Python execute_process( - COMMAND ${HDF5_${language}_COMPILER_EXECUTABLE} ${test_file} - WORKING_DIRECTORY ${scratch_dir} + COMMAND ${HDF5_${language}_COMPILER_EXECUTABLE} "${_HDF5_TEST_SRC}" + WORKING_DIRECTORY ${_HDF5_TEST_DIR} OUTPUT_VARIABLE output ERROR_VARIABLE output RESULT_VARIABLE return_value ) - if(return_value AND NOT HDF5_FIND_QUIETLY) - message(STATUS - "HDF5 ${language} compiler wrapper is unable to compile a minimal HDF5 program.") + if(NOT return_value EQUAL 0) + message(CONFIGURE_LOG + "HDF5 ${language} compiler wrapper is unable to compile a minimal HDF5 program.\n\n${output}") + if(NOT HDF5_FIND_QUIETLY) + message(STATUS + "HDF5 ${language} compiler wrapper is unable to compile a minimal HDF5 program.") + endif() else() execute_process( - COMMAND ${HDF5_${language}_COMPILER_EXECUTABLE} -show ${lib_type_args} ${test_file} - WORKING_DIRECTORY ${scratch_dir} + COMMAND ${HDF5_${language}_COMPILER_EXECUTABLE} -show ${lib_type_args} "${_HDF5_TEST_SRC}" + WORKING_DIRECTORY ${_HDF5_TEST_DIR} OUTPUT_VARIABLE output ERROR_VARIABLE output RESULT_VARIABLE return_value OUTPUT_STRIP_TRAILING_WHITESPACE ) - if(return_value AND NOT HDF5_FIND_QUIETLY) - message(STATUS - "Unable to determine HDF5 ${language} flags from HDF5 wrapper.") + if(NOT return_value EQUAL 0) + message(CONFIGURE_LOG + "Unable to determine HDF5 ${language} flags from HDF5 wrapper.\n\n${output}") + if(NOT HDF5_FIND_QUIETLY) + message(STATUS + "Unable to determine HDF5 ${language} flags from HDF5 wrapper.") + endif() endif() execute_process( COMMAND ${HDF5_${language}_COMPILER_EXECUTABLE} -showconfig @@ -399,9 +387,13 @@ function( _HDF5_invoke_compiler language output_var return_value_var version_var RESULT_VARIABLE return_value OUTPUT_STRIP_TRAILING_WHITESPACE ) - if(return_value AND NOT HDF5_FIND_QUIETLY) - message(STATUS - "Unable to determine HDF5 ${language} version_var from HDF5 wrapper.") + if(NOT return_value EQUAL 0) + message(CONFIGURE_LOG + "Unable to determine HDF5 ${language} version_var from HDF5 wrapper.\n\n${output}") + if(NOT HDF5_FIND_QUIETLY) + message(STATUS + "Unable to determine HDF5 ${language} version_var from HDF5 wrapper.") + endif() endif() string(REGEX MATCH "HDF5 Version: ([a-zA-Z0-9\\.\\-]*)" version "${config_output}") if(version) @@ -599,6 +591,7 @@ endif() if(NOT HDF5_FOUND) set(_HDF5_NEED_TO_SEARCH FALSE) + set(_HDF5_TEST_DIR ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/hdf5) set(HDF5_COMPILER_NO_INTERROGATE TRUE) # Only search for languages we've enabled foreach(_lang IN LISTS HDF5_LANGUAGE_BINDINGS) @@ -607,16 +600,23 @@ if(NOT HDF5_FOUND) # First check to see if our regular compiler is one of wrappers if(_lang STREQUAL "C") + set(_HDF5_TEST_SRC cmake_hdf5_test.c) + if(CMAKE_CXX_COMPILER_LOADED AND NOT CMAKE_C_COMPILER_LOADED) + # CXX project without C enabled + set(_HDF5_TEST_SRC cmake_hdf5_test.cxx) + endif() _HDF5_test_regular_compiler_C( HDF5_${_lang}_COMPILER_NO_INTERROGATE HDF5_${_lang}_VERSION HDF5_${_lang}_IS_PARALLEL) elseif(_lang STREQUAL "CXX") + set(_HDF5_TEST_SRC cmake_hdf5_test.cxx) _HDF5_test_regular_compiler_CXX( HDF5_${_lang}_COMPILER_NO_INTERROGATE HDF5_${_lang}_VERSION HDF5_${_lang}_IS_PARALLEL) elseif(_lang STREQUAL "Fortran") + set(_HDF5_TEST_SRC cmake_hdf5_test.f90) _HDF5_test_regular_compiler_Fortran( HDF5_${_lang}_COMPILER_NO_INTERROGATE HDF5_${_lang}_IS_PARALLEL) @@ -762,6 +762,8 @@ if(NOT HDF5_FOUND) endif() endif() endforeach() + unset(_HDF5_TEST_DIR) + unset(_HDF5_TEST_SRC) unset(_lib) else() set(_HDF5_NEED_TO_SEARCH TRUE) diff --git a/Modules/FindMatlab.cmake b/Modules/FindMatlab.cmake index 0f1e451..e111b79 100644 --- a/Modules/FindMatlab.cmake +++ b/Modules/FindMatlab.cmake @@ -137,6 +137,12 @@ Result variables ``Matlab_FOUND`` ``TRUE`` if the Matlab installation is found, ``FALSE`` otherwise. All variable below are defined if Matlab is found. +``Matlab_VERSION`` + .. versionadded:: 3.27 + + the numerical version (e.g. 9.13) of Matlab found. Not to be confused with + Matlab release name (e.g. R2022b) that can be obtained with + :command:`matlab_get_release_name_from_version`. ``Matlab_ROOT_DIR`` the final root of the Matlab installation determined by the FindMatlab module. @@ -296,6 +302,7 @@ if(NOT MATLAB_ADDITIONAL_VERSIONS) endif() set(MATLAB_VERSIONS_MAPPING + "R2023a=9.14" "R2022b=9.13" "R2022a=9.12" "R2021b=9.11" @@ -336,7 +343,14 @@ endif() #[=======================================================================[.rst: .. command:: matlab_get_version_from_release_name - Returns the version of Matlab (17.58) from a release name (R2017k) + .. code-block:: cmake + + matlab_get_version_from_release_name(release version) + + * Input: ``release`` is the release name (R2022b) + * Output: ``version`` is the version of Matlab (9.13) + + Returns the version of Matlab from a release name #]=======================================================================] macro(matlab_get_version_from_release_name release_name version_name) @@ -353,13 +367,17 @@ macro(matlab_get_version_from_release_name release_name version_name) endmacro() +#[=======================================================================[.rst: +.. command:: matlab_get_release_name_from_version + .. code-block:: cmake + matlab_get_release_name_from_version(version release_name) -#[=======================================================================[.rst: -.. command:: matlab_get_release_name_from_version + * Input: ``version`` is the version of Matlab (9.13) + * Output: ``release_name`` is the release name (R2022b) - Returns the release name (R2017k) from the version of Matlab (17.58) + Returns the release name from the version of Matlab #]=======================================================================] macro(matlab_get_release_name_from_version version release_name) @@ -370,7 +388,7 @@ macro(matlab_get_release_name_from_version version release_name) set(${release_name} ${CMAKE_MATCH_1}) break() endif() - endforeach(_var) + endforeach() unset(_var) unset(_matched) @@ -381,10 +399,7 @@ macro(matlab_get_release_name_from_version version release_name) endmacro() - - - -# extracts all the supported release names (R2017k...) of Matlab +# extracts all the supported release names (R2022b...) of Matlab # internal use macro(matlab_get_supported_releases list_releases) set(${list_releases}) @@ -395,7 +410,7 @@ macro(matlab_get_supported_releases list_releases) endif() unset(_matched) unset(CMAKE_MATCH_1) - endforeach(_var) + endforeach() unset(_var) endmacro() @@ -412,7 +427,7 @@ macro(matlab_get_supported_versions list_versions) endif() unset(_matched) unset(CMAKE_MATCH_1) - endforeach(_var) + endforeach() unset(_var) endmacro() @@ -420,8 +435,15 @@ endmacro() #[=======================================================================[.rst: .. command:: matlab_extract_all_installed_versions_from_registry - This function parses the registry and founds the Matlab versions that are - installed. The found versions are returned in `matlab_versions`. + .. code-block:: cmake + + matlab_extract_all_installed_versions_from_registry(win64 matlab_versions) + + * Input: ``win64`` is a boolean to search for the 64 bit version of Matlab + * Output: ``matlab_versions`` is a list of all the versions of Matlab found + + This function parses the Windows registry and founds the Matlab versions that + are installed. The found versions are returned in `matlab_versions`. Set `win64` to `TRUE` if the 64 bit version of Matlab should be looked for The returned list contains all versions under ``HKLM\\SOFTWARE\\Mathworks\\MATLAB`` and @@ -504,31 +526,6 @@ macro(extract_matlab_versions_from_registry_brute_force matlab_versions) set(matlab_supported_versions) matlab_get_supported_versions(matlab_supported_versions) - - # this is a manual population of the versions we want to look for - # this can be done as is, but preferably with the call to - # matlab_get_supported_versions and variable - - # populating the versions we want to look for - # set(matlab_supported_versions) - - # # Matlab 7 - # set(matlab_major 7) - # foreach(current_matlab_minor RANGE 4 20) - # list(APPEND matlab_supported_versions "${matlab_major}.${current_matlab_minor}") - # endforeach(current_matlab_minor) - - # # Matlab 8 - # set(matlab_major 8) - # foreach(current_matlab_minor RANGE 0 5) - # list(APPEND matlab_supported_versions "${matlab_major}.${current_matlab_minor}") - # endforeach(current_matlab_minor) - - # # taking into account the possible additional versions provided by the user - # if(DEFINED MATLAB_ADDITIONAL_VERSIONS) - # list(APPEND matlab_supported_versions MATLAB_ADDITIONAL_VERSIONS) - # endif() - # we order from more recent to older if(matlab_supported_versions) list(REMOVE_DUPLICATES matlab_supported_versions) @@ -540,8 +537,6 @@ macro(extract_matlab_versions_from_registry_brute_force matlab_versions) endmacro() - - #[=======================================================================[.rst: .. command:: matlab_get_all_valid_matlab_roots_from_registry @@ -551,16 +546,12 @@ endmacro() ``(type,version_number,matlab_root_path)``, where ``type`` indicates either ``MATLAB`` or ``MCR``. - :: + .. code-block:: cmake - matlab_get_all_valid_matlab_roots_from_registry( - matlab_versions - matlab_roots) + matlab_get_all_valid_matlab_roots_from_registry(matlab_versions matlab_roots) - ``matlab_versions`` - the versions of each of the Matlab or MCR installations - ``matlab_roots`` - the location of each of the Matlab or MCR installations + * Input: ``matlab_versions`` of each of the Matlab or MCR installations + * Output: ``matlab_roots`` location of each of the Matlab or MCR installations #]=======================================================================] function(matlab_get_all_valid_matlab_roots_from_registry matlab_versions matlab_roots) @@ -570,7 +561,7 @@ function(matlab_get_all_valid_matlab_roots_from_registry matlab_versions matlab_ set(_matlab_roots_list ) # check for Matlab installations - foreach(_matlab_current_version ${matlab_versions}) + foreach(_matlab_current_version IN LISTS matlab_versions) get_filename_component( current_MATLAB_ROOT "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MathWorks\\MATLAB\\${_matlab_current_version};MATLABROOT]" @@ -583,7 +574,7 @@ function(matlab_get_all_valid_matlab_roots_from_registry matlab_versions matlab_ endforeach() # Check for MCR installations - foreach(_matlab_current_version ${matlab_versions}) + foreach(_matlab_current_version IN LISTS matlab_versions) get_filename_component( current_MATLAB_ROOT "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MathWorks\\MATLAB Runtime\\${_matlab_current_version};MATLABROOT]" @@ -599,7 +590,7 @@ function(matlab_get_all_valid_matlab_roots_from_registry matlab_versions matlab_ endforeach() # Check for old MCR installations - foreach(_matlab_current_version ${matlab_versions}) + foreach(_matlab_current_version IN LISTS matlab_versions) get_filename_component( current_MATLAB_ROOT "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MathWorks\\MATLAB Compiler Runtime\\${_matlab_current_version};MATLABROOT]" @@ -623,16 +614,12 @@ endfunction() This function should not be called before the appropriate Matlab root has been found. - :: + .. code-block:: cmake - matlab_get_mex_suffix( - matlab_root - mex_suffix) + matlab_get_mex_suffix(matlab_root mex_suffix) - ``matlab_root`` - the root of the Matlab/MCR installation - ``mex_suffix`` - the variable name in which the suffix will be returned. + * Input: ``matlab_root`` root of Matlab/MCR install e.g. ``Matlab_ROOT_DIR`` + * Output: ``mex_suffix`` variable name in which the suffix will be returned. #]=======================================================================] function(matlab_get_mex_suffix matlab_root mex_suffix) @@ -710,8 +697,6 @@ function(matlab_get_mex_suffix matlab_root mex_suffix) endfunction() - - #[=======================================================================[.rst: .. command:: matlab_get_version_from_matlab_run @@ -719,16 +704,12 @@ endfunction() version. If the path provided for the Matlab installation points to an MCR installation, the version is extracted from the installed files. - :: + .. code-block:: cmake - matlab_get_version_from_matlab_run( - matlab_binary_path - matlab_list_versions) + matlab_get_version_from_matlab_run(matlab_binary_path matlab_list_versions) - ``matlab_binary_path`` - the location of the `matlab` binary executable - ``matlab_list_versions`` - the version extracted from Matlab + * Input: ``matlab_binary_path`` path of the `matlab` binary executable + * Output: ``matlab_list_versions`` the version extracted from Matlab #]=======================================================================] function(matlab_get_version_from_matlab_run matlab_binary_program matlab_list_versions) @@ -898,7 +879,7 @@ endfunction() non 0 failure). Additional arguments accepted by :command:`add_test` can be passed through ``TEST_ARGS`` (eg. ``CONFIGURATION <config> ...``). - :: + .. code-block:: cmake matlab_add_unit_test( NAME <name> @@ -912,7 +893,7 @@ endfunction() [NO_UNITTEST_FRAMEWORK] ) - The function arguments are: + Function Parameters: ``NAME`` name of the unittest in ctest. @@ -1010,7 +991,7 @@ endfunction() for the MEX file. Remaining arguments of the call are passed to the :command:`add_library` or :command:`add_executable` command. - :: + .. code-block:: cmake matlab_add_mex( NAME <name> @@ -1025,6 +1006,8 @@ endfunction() [...] ) + Function Parameters: + ``NAME`` name of the target. ``SRC`` @@ -1209,18 +1192,17 @@ function(matlab_add_mex) if (MSVC) - set(_link_flags "${_link_flags} /EXPORT:mexFunction") + string(APPEND _link_flags " /EXPORT:mexFunction") if(NOT Matlab_VERSION_STRING VERSION_LESS "9.1") # For 9.1 (R2016b) and newer, export version - set(_link_flags "${_link_flags} /EXPORT:mexfilerequiredapiversion") + string(APPEND _link_flags " /EXPORT:mexfilerequiredapiversion") endif() set_property(TARGET ${${prefix}_NAME} APPEND PROPERTY LINK_FLAGS ${_link_flags}) endif() # No other compiler currently supported on Windows. - set_target_properties(${${prefix}_NAME} - PROPERTIES - DEFINE_SYMBOL "DLL_EXPORT_SYM=__declspec(dllexport)") + set_property(TARGET ${${prefix}_NAME} PROPERTY + DEFINE_SYMBOL "DLL_EXPORT_SYM=__declspec(dllexport)") else() @@ -1246,7 +1228,7 @@ function(matlab_add_mex) if(Matlab_HAS_CPP_API) list(APPEND _ver_map_files ${Matlab_EXTERN_LIBRARY_DIR}/cppMexFunction.map) # This one doesn't exist on Linux - set(_link_flags "${_link_flags} -Wl,-U,_mexCreateMexFunction -Wl,-U,_mexDestroyMexFunction -Wl,-U,_mexFunctionAdapter") + string(APPEND _link_flags " -Wl,-U,_mexCreateMexFunction -Wl,-U,_mexDestroyMexFunction -Wl,-U,_mexFunctionAdapter") # On MacOS, the MEX command adds the above, without it the link breaks # because we indiscriminately use "cppMexFunction.map" even for C API MEX-files. endif() @@ -1261,14 +1243,14 @@ function(matlab_add_mex) target_compile_options(${${prefix}_NAME} PRIVATE "-pthread") endif() - set(_link_flags "${_link_flags} -Wl,--as-needed") + string(APPEND _link_flags " -Wl,--as-needed") set(_export_flag_name --version-script) endif() - foreach(_file ${_ver_map_files}) - set(_link_flags "${_link_flags} -Wl,${_export_flag_name},${_file}") + foreach(_file IN LISTS _ver_map_files) + string(APPEND _link_flags " -Wl,${_export_flag_name},${_file}") endforeach() # The `mex` command doesn't add this define. It is specified here in order @@ -2020,11 +2002,13 @@ _Matlab_add_imported_target(MAT mat) _Matlab_add_imported_target(ENGINE MatlabEngine) _Matlab_add_imported_target(DATAARRAY MatlabDataArray) +set(Matlab_VERSION ${Matlab_VERSION_STRING}) + find_package_handle_standard_args( Matlab FOUND_VAR Matlab_FOUND REQUIRED_VARS ${_matlab_required_variables} - VERSION_VAR Matlab_VERSION_STRING + VERSION_VAR Matlab_VERSION HANDLE_COMPONENTS) unset(_matlab_required_variables) diff --git a/Modules/FindOpenAL.cmake b/Modules/FindOpenAL.cmake index 53aafdc..3d58569 100644 --- a/Modules/FindOpenAL.cmake +++ b/Modules/FindOpenAL.cmake @@ -105,18 +105,16 @@ find_package_handle_standard_args( mark_as_advanced(OPENAL_LIBRARY OPENAL_INCLUDE_DIR) -if(OPENAL_INCLUDE_DIR AND OPENAL_LIBRARY) - if(NOT TARGET OpenAL::OpenAL) - if(EXISTS "${OPENAL_LIBRARY}") - add_library(OpenAL::OpenAL UNKNOWN IMPORTED) - set_target_properties(OpenAL::OpenAL PROPERTIES - IMPORTED_LOCATION "${OPENAL_LIBRARY}") - else() - add_library(OpenAL::OpenAL INTERFACE IMPORTED) - set_target_properties(OpenAL::OpenAL PROPERTIES - IMPORTED_LIBNAME "${OPENAL_LIBRARY}") - endif() +if(OPENAL_FOUND AND NOT TARGET OpenAL::OpenAL) + if(OPENAL_LIBRARY MATCHES "/([^/]+)\\.framework$") + add_library(OpenAL::OpenAL INTERFACE IMPORTED) set_target_properties(OpenAL::OpenAL PROPERTIES - INTERFACE_INCLUDE_DIRECTORIES "${OPENAL_INCLUDE_DIR}") + INTERFACE_LINK_LIBRARIES "${OPENAL_LIBRARY}") + else() + add_library(OpenAL::OpenAL UNKNOWN IMPORTED) + set_target_properties(OpenAL::OpenAL PROPERTIES + IMPORTED_LOCATION "${OPENAL_LIBRARY}") endif() + set_target_properties(OpenAL::OpenAL PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${OPENAL_INCLUDE_DIR}") endif() diff --git a/Modules/FindOpenGL.cmake b/Modules/FindOpenGL.cmake index a9a1b2a..a773601 100644 --- a/Modules/FindOpenGL.cmake +++ b/Modules/FindOpenGL.cmake @@ -18,8 +18,26 @@ Optional COMPONENTS .. versionadded:: 3.10 -This module respects several optional COMPONENTS: ``EGL``, ``GLX``, and -``OpenGL``. There are corresponding import targets for each of these flags. +This module respects several optional COMPONENTS: + +``EGL`` + The EGL interface between OpenGL, OpenGL ES and the underlying windowing system. + +``GLX`` + An extension to X that interfaces OpenGL, OpenGL ES with X window system. + +``OpenGL`` + The cross platform API for 3D graphics. + +``GLES2`` + .. versionadded:: 3.27 + + A subset of OpenGL API for embedded systems with limited capabilities. + +``GLES3`` + .. versionadded:: 3.27 + + A subset of OpenGL API for embedded systems with more capabilities. IMPORTED Targets ^^^^^^^^^^^^^^^^ @@ -42,6 +60,14 @@ This module defines the :prop_tgt:`IMPORTED` targets: Defined if the system has OpenGL Extension to the X Window System (GLX). ``OpenGL::EGL`` Defined if the system has EGL. +``OpenGL::GLES2`` + .. versionadded:: 3.27 + + Defined if the system has GLES2. +``OpenGL::GLES3`` + .. versionadded:: 3.27 + + Defined if the system has GLES3. Result Variables ^^^^^^^^^^^^^^^^ @@ -60,6 +86,10 @@ This module sets the following variables: True, if the system has GLX. ``OpenGL_EGL_FOUND`` True, if the system has EGL. +``OpenGL::GLES2`` + Defined if the system has GLES2. +``OpenGL::GLES3`` + Defined if the system has GLES3. ``OPENGL_INCLUDE_DIR`` Path to the OpenGL include directory. ``OPENGL_EGL_INCLUDE_DIRS`` @@ -88,6 +118,14 @@ The following cache variables may also be set: ``OPENGL_gl_LIBRARY`` Path to the OpenGL library. New code should prefer the ``OpenGL::*`` import targets. +``OPENGL_gles2_LIBRARY`` + .. versionadded:: 3.27 + + Path to the OpenGL GLES2 library. +``OPENGL_gles3_LIBRARY`` + .. versionadded:: 3.27 + + Path to the OpenGL GLES3 library. .. versionadded:: 3.10 Variables for GLVND-specific libraries ``OpenGL``, ``EGL`` and ``GLX``. @@ -182,7 +220,10 @@ elseif (APPLE) OPENGL_glu_LIBRARY ) else() - if (CMAKE_SYSTEM_NAME MATCHES "HP-UX") + if (CMAKE_ANDROID_NDK) + set(_OPENGL_INCLUDE_PATH ${CMAKE_ANDROID_NDK}/sysroot/usr/include) + set(_OPENGL_LIB_PATH ${CMAKE_ANDROID_NDK}/platforms/android-${CMAKE_SYSTEM_VERSION}/arch-${CMAKE_ANDROID_ARCH}/usr/lib) + elseif (CMAKE_SYSTEM_NAME MATCHES "HP-UX") # Handle HP-UX cases where we only want to find OpenGL in either hpux64 # or hpux32 depending on if we're doing a 64 bit build. if(CMAKE_SIZEOF_VOID_P EQUAL 4) @@ -198,6 +239,13 @@ else() /boot/develop/lib/x86) set(_OPENGL_INCLUDE_PATH /boot/develop/headers/os/opengl) + elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux") + # CMake doesn't support arbitrary globs in search paths. + file(GLOB _OPENGL_LIB_PATH + # The NVidia driver installation tool on Linux installs libraries to a + # `nvidia-<version>` subdirectory. + "/usr/lib/nvidia-*" + "/usr/lib32/nvidia-*") endif() # The first line below is to make sure that the proper headers @@ -215,15 +263,20 @@ else() ) find_path(OPENGL_GLX_INCLUDE_DIR GL/glx.h ${_OPENGL_INCLUDE_PATH}) find_path(OPENGL_EGL_INCLUDE_DIR EGL/egl.h ${_OPENGL_INCLUDE_PATH}) + find_path(OPENGL_GLES2_INCLUDE_DIR GLES2/gl2.h ${_OPENGL_INCLUDE_PATH}) + find_path(OPENGL_GLES3_INCLUDE_DIR GLES3/gl3.h ${_OPENGL_INCLUDE_PATH}) find_path(OPENGL_xmesa_INCLUDE_DIR GL/xmesa.h /usr/share/doc/NVIDIA_GLX-1.0/include /usr/openwin/share/include /opt/graphics/OpenGL/include ) + list(APPEND _OpenGL_CACHE_VARS OPENGL_INCLUDE_DIR OPENGL_GLX_INCLUDE_DIR OPENGL_EGL_INCLUDE_DIR + OPENGL_GLES2_INCLUDE_DIR + OPENGL_GLES3_INCLUDE_DIR OPENGL_xmesa_INCLUDE_DIR ) @@ -246,6 +299,17 @@ else() PATH_SUFFIXES libglvnd ) + find_library(OPENGL_gles2_LIBRARY + NAMES GLESv2 + PATHS ${_OPENGL_LIB_PATH} + ) + + find_library(OPENGL_gles3_LIBRARY + NAMES GLESv3 + GLESv2 # mesa provides only libGLESv2 + PATHS ${_OPENGL_LIB_PATH} + ) + find_library(OPENGL_glu_LIBRARY NAMES GLU MesaGLU PATHS ${OPENGL_gl_LIBRARY} @@ -258,6 +322,8 @@ else() OPENGL_opengl_LIBRARY OPENGL_glx_LIBRARY OPENGL_egl_LIBRARY + OPENGL_gles2_LIBRARY + OPENGL_gles3_LIBRARY OPENGL_glu_LIBRARY ) @@ -338,12 +404,16 @@ else() OPENGL_glx_LIBRARY AND NOT OPENGL_gl_LIBRARY) OR (NOT OPENGL_USE_EGL AND + NOT OPENGL_USE_GLES3 AND + NOT OPENGL_USE_GLES2 AND NOT OPENGL_glx_LIBRARY AND NOT OPENGL_gl_LIBRARY) OR (NOT OPENGL_USE_EGL AND OPENGL_opengl_LIBRARY AND OPENGL_glx_LIBRARY) OR - ( OPENGL_USE_EGL)) + (NOT OPENGL_USE_GLES3 AND + NOT OPENGL_USE_GLES2 AND + OPENGL_USE_EGL)) list(APPEND _OpenGL_REQUIRED_VARS OPENGL_opengl_LIBRARY) endif() @@ -351,13 +421,19 @@ else() if((NOT OPENGL_USE_OPENGL AND NOT OPENGL_USE_GLX AND NOT OPENGL_USE_EGL AND + NOT OPENGL_USE_GLES3 AND + NOT OPENGL_USE_GLES2 AND NOT OPENGL_glx_LIBRARY AND NOT OPENGL_gl_LIBRARY) OR ( OPENGL_USE_GLX AND NOT OPENGL_USE_EGL AND + NOT OPENGL_USE_GLES3 AND + NOT OPENGL_USE_GLES2 AND NOT OPENGL_glx_LIBRARY AND NOT OPENGL_gl_LIBRARY) OR (NOT OPENGL_USE_EGL AND + NOT OPENGL_USE_GLES3 AND + NOT OPENGL_USE_GLES2 AND OPENGL_opengl_LIBRARY AND OPENGL_glx_LIBRARY) OR (OPENGL_USE_GLX AND OPENGL_USE_EGL)) @@ -369,6 +445,16 @@ else() list(APPEND _OpenGL_REQUIRED_VARS OPENGL_egl_LIBRARY) endif() + # GLVND GLES2 library. + if(OPENGL_USE_GLES2) + list(APPEND _OpenGL_REQUIRED_VARS OPENGL_gles2_LIBRARY) + endif() + + # GLVND GLES3 library. + if(OPENGL_USE_GLES3) + list(APPEND _OpenGL_REQUIRED_VARS OPENGL_gles3_LIBRARY) + endif() + # Old-style "libGL" library: used as a fallback when GLVND isn't available. if((NOT OPENGL_USE_EGL AND NOT OPENGL_opengl_LIBRARY AND @@ -381,7 +467,11 @@ else() endif() # We always need the 'gl.h' include dir. - list(APPEND _OpenGL_REQUIRED_VARS OPENGL_INCLUDE_DIR) + if(OPENGL_USE_EGL) + list(APPEND _OpenGL_REQUIRED_VARS OPENGL_EGL_INCLUDE_DIR) + else() + list(APPEND _OpenGL_REQUIRED_VARS OPENGL_INCLUDE_DIR) + endif() unset(_OPENGL_INCLUDE_PATH) unset(_OPENGL_LIB_PATH) @@ -428,6 +518,18 @@ else() set(OpenGL_EGL_FOUND FALSE) endif() +if(OPENGL_gles2_LIBRARY AND OPENGL_GLES2_INCLUDE_DIR) + set(OpenGL_GLES2_FOUND TRUE) +else() + set(OpenGL_GLES2_FOUND FALSE) +endif() + +if(OPENGL_gles3_LIBRARY AND OPENGL_GLES3_INCLUDE_DIR) + set(OpenGL_GLES3_FOUND TRUE) +else() + set(OpenGL_GLES3_FOUND FALSE) +endif() + # User-visible names should be plural. if(OPENGL_EGL_INCLUDE_DIR) set(OPENGL_EGL_INCLUDE_DIRS ${OPENGL_EGL_INCLUDE_DIR}) @@ -461,6 +563,7 @@ if(OPENGL_FOUND) endif() set_target_properties(OpenGL::OpenGL PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${OPENGL_INCLUDE_DIR}") + set(_OpenGL_EGL_IMPL OpenGL::OpenGL) endif() # ::GLX is a GLVND library, and thus Linux-only: we don't bother checking @@ -481,6 +584,73 @@ if(OPENGL_FOUND) "${OPENGL_GLX_INCLUDE_DIR}") endif() + # ::GLES2 is a GLVND library, and thus Linux-only: we don't bother checking + # for a framework version of this library. + if(OpenGL_GLES2_FOUND AND NOT TARGET OpenGL::GLES2) + + # Initialize target + if(NOT OPENGL_gles2_LIBRARY) + add_library(OpenGL::GLES2 INTERFACE IMPORTED) + else() + if(IS_ABSOLUTE "${OPENGL_gles2_LIBRARY}") + add_library(OpenGL::GLES2 UNKNOWN IMPORTED) + set_target_properties(OpenGL::GLES2 PROPERTIES + IMPORTED_LOCATION "${OPENGL_gles2_LIBRARY}" + ) + else() + add_library(OpenGL::GLES2 INTERFACE IMPORTED) + set_target_properties(OpenGL::GLES2 PROPERTIES + IMPORTED_LIBNAME "${OPENGL_gles2_LIBRARY}" + ) + endif() + endif() + + # Attach target properties + set_target_properties(OpenGL::GLES2 + PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES + "${OPENGL_GLES2_INCLUDE_DIR}" + ) + + if (OPENGL_USE_GLES2) + set(_OpenGL_EGL_IMPL OpenGL::GLES2) + endif () + + endif() + + # ::GLES3 is a GLVND library, and thus Linux-only: we don't bother checking + # for a framework version of this library. + if(OpenGL_GLES3_FOUND AND NOT TARGET OpenGL::GLES3) + + # Initialize target + if(NOT OPENGL_gles3_LIBRARY) + add_library(OpenGL::GLES3 INTERFACE IMPORTED) + else() + if(IS_ABSOLUTE "${OPENGL_gles3_LIBRARY}") + add_library(OpenGL::GLES3 UNKNOWN IMPORTED) + set_target_properties(OpenGL::GLES3 PROPERTIES + IMPORTED_LOCATION "${OPENGL_gles3_LIBRARY}" + ) + else() + add_library(OpenGL::GLES3 INTERFACE IMPORTED) + set_target_properties(OpenGL::GLES3 PROPERTIES + IMPORTED_LIBNAME "${OPENGL_gles3_LIBRARY}" + ) + endif() + endif() + + # Attach target properties + set_target_properties(OpenGL::GLES3 PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES + "${OPENGL_GLES3_INCLUDE_DIR}" + ) + + if (OPENGL_USE_GLES3) + set(_OpenGL_EGL_IMPL OpenGL::GLES3) + endif () + + endif() + if(OPENGL_gl_LIBRARY AND NOT TARGET OpenGL::GL) # A legacy GL library is available, so use it for the legacy GL target. if(IS_ABSOLUTE "${OPENGL_gl_LIBRARY}") @@ -517,10 +687,9 @@ if(OPENGL_FOUND) # ::EGL is a GLVND library, and thus Linux-only: we don't bother checking # for a framework version of this library. - # Note we test for OpenGL::OpenGL as a target. When this module is updated to - # support GLES, we would additionally want to check for the hypothetical GLES - # target and enable EGL if either ::GLES or ::OpenGL is created. - if(TARGET OpenGL::OpenGL AND OpenGL_EGL_FOUND AND NOT TARGET OpenGL::EGL) + # Note we test whether _OpenGL_EGL_IMPL is set. Based on the OpenGL implementation, + # _OpenGL_EGL_IMPL will be one of OpenGL::OpenGL, OpenGL::GLES2, OpenGL::GLES3 + if(_OpenGL_EGL_IMPL AND OpenGL_EGL_FOUND AND NOT TARGET OpenGL::EGL) if(IS_ABSOLUTE "${OPENGL_egl_LIBRARY}") add_library(OpenGL::EGL UNKNOWN IMPORTED) set_target_properties(OpenGL::EGL PROPERTIES IMPORTED_LOCATION @@ -531,7 +700,7 @@ if(OPENGL_FOUND) "${OPENGL_egl_LIBRARY}") endif() set_target_properties(OpenGL::EGL PROPERTIES INTERFACE_LINK_LIBRARIES - OpenGL::OpenGL) + "${_OpenGL_EGL_IMPL}") # Note that EGL's include directory is different from OpenGL/GLX's! set_target_properties(OpenGL::EGL PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${OPENGL_EGL_INCLUDE_DIR}") diff --git a/Modules/FindPython.cmake b/Modules/FindPython.cmake index fd2eeaa..31ef1c7 100644 --- a/Modules/FindPython.cmake +++ b/Modules/FindPython.cmake @@ -542,7 +542,7 @@ If the library type is not specified, ``MODULE`` is assumed. was introduced. Specifying only major version ``3`` is equivalent to ``3.2``. When option ``WITH_SOABI`` is also specified, the module suffix will include - the ``Python3_SOSABI`` value, if any. + the ``Python_SOSABI`` value, if any. #]=======================================================================] diff --git a/Modules/FindPython/Support.cmake b/Modules/FindPython/Support.cmake index f1be0f4..60d2296 100644 --- a/Modules/FindPython/Support.cmake +++ b/Modules/FindPython/Support.cmake @@ -192,28 +192,25 @@ function (_PYTHON_GET_REGISTRIES _PYTHON_PGR_REGISTRY_PATHS) if (implementation STREQUAL "CPython") foreach (version IN LISTS _PGR_VERSION) string (REPLACE "." "" version_no_dots ${version}) - list (APPEND registries - [HKEY_CURRENT_USER/SOFTWARE/Python/PythonCore/${version}-${_${_PYTHON_PREFIX}_ARCH}/InstallPath] - [HKEY_CURRENT_USER/SOFTWARE/Python/PythonCore/${version}-${_${_PYTHON_PREFIX}_ARCH2}/InstallPath]) + list (TRANSFORM _${_PYTHON_PREFIX}_ARCH REPLACE "^(.+)$" "[HKEY_CURRENT_USER/SOFTWARE/Python/PythonCore/${version}-\\1/InstallPath]" OUTPUT_VARIABLE reg_paths) + list (APPEND registries ${reg_paths}) if (version VERSION_GREATER_EQUAL "3.5") # cmake_host_system_information is not usable in bootstrap get_filename_component (arch "[HKEY_CURRENT_USER\\Software\\Python\\PythonCore\\${version};SysArchitecture]" NAME) - if (arch MATCHES "(${_${_PYTHON_PREFIX}_ARCH}|${_${_PYTHON_PREFIX}_ARCH2})bit") - list (APPEND registries - [HKEY_CURRENT_USER/SOFTWARE/Python/PythonCore/${version}/InstallPath]) + string (REPLACE "bit" "" arch "${arch}") + if (arch IN_LIST _${_PYTHON_PREFIX}_ARCH) + list (APPEND registries [HKEY_CURRENT_USER/SOFTWARE/Python/PythonCore/${version}/InstallPath]) endif() else() - list (APPEND registries - [HKEY_CURRENT_USER/SOFTWARE/Python/PythonCore/${version}/InstallPath]) - endif() - list (APPEND registries - [HKEY_CURRENT_USER/SOFTWARE/Python/ContinuumAnalytics/Anaconda${version_no_dots}-${_${_PYTHON_PREFIX}_ARCH}/InstallPath] - [HKEY_CURRENT_USER/SOFTWARE/Python/ContinuumAnalytics/Anaconda${version_no_dots}-${_${_PYTHON_PREFIX}_ARCH2}/InstallPath] - [HKEY_LOCAL_MACHINE/SOFTWARE/Python/PythonCore/${version}-${_${_PYTHON_PREFIX}_ARCH}/InstallPath] - [HKEY_LOCAL_MACHINE/SOFTWARE/Python/PythonCore/${version}-${_${_PYTHON_PREFIX}_ARCH2}/InstallPath] - [HKEY_LOCAL_MACHINE/SOFTWARE/Python/PythonCore/${version}/InstallPath] - [HKEY_LOCAL_MACHINE/SOFTWARE/Python/ContinuumAnalytics/Anaconda${version_no_dots}-${_${_PYTHON_PREFIX}_ARCH}/InstallPath] - [HKEY_LOCAL_MACHINE/SOFTWARE/Python/ContinuumAnalytics/Anaconda${version_no_dots}-${_${_PYTHON_PREFIX}_ARCH2}/InstallPath]) + list (APPEND registries [HKEY_CURRENT_USER/SOFTWARE/Python/PythonCore/${version}/InstallPath]) + endif() + list (TRANSFORM _${_PYTHON_PREFIX}_ARCH REPLACE "^(.+)$" "[HKEY_CURRENT_USER/SOFTWARE/Python/ContinuumAnalytics/Anaconda${version_no_dots}-\\1/InstallPath]" OUTPUT_VARIABLE reg_paths) + list (APPEND registries ${reg_paths}) + list (TRANSFORM _${_PYTHON_PREFIX}_ARCH REPLACE "^(.+)$" "[HKEY_CURRENT_USER/SOFTWARE/Python/PythonCore/${version}-\\1/InstallPath]" OUTPUT_VARIABLE reg_paths) + list (APPEND registries ${reg_paths}) + list (APPEND registries [HKEY_LOCAL_MACHINE/SOFTWARE/Python/PythonCore/${version}/InstallPath]) + list (TRANSFORM _${_PYTHON_PREFIX}_ARCH REPLACE "^(.+)$" "[HKEY_LOCAL_MACHINE/SOFTWARE/Python/ContinuumAnalytics/Anaconda${version_no_dots}-\\1/InstallPath]" OUTPUT_VARIABLE reg_paths) + list (APPEND registries ${reg_paths}) endforeach() elseif (implementation STREQUAL "IronPython") foreach (version IN LISTS _PGR_VERSION) @@ -579,7 +576,7 @@ function (_PYTHON_GET_CONFIG_VAR _PYTHON_PGCV_VALUE NAME) endif() endif() elseif (NAME STREQUAL "SOSABI") - execute_process (COMMAND ${_${_PYTHON_PREFIX}_INTERPRETER_LAUNCHER} "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c "import sys\nimport re\nimport importlib\nsys.stdout.write(next(filter(lambda x: re.search('^\\.abi', x), importlib.machinery.EXTENSION_SUFFIXES)))" + execute_process (COMMAND ${_${_PYTHON_PREFIX}_INTERPRETER_LAUNCHER} "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c "import sys\nimport re\nimport importlib.machinery\nsys.stdout.write(next(filter(lambda x: re.search('^\\.abi', x), importlib.machinery.EXTENSION_SUFFIXES)))" RESULT_VARIABLE _result OUTPUT_VARIABLE _values ERROR_QUIET @@ -927,6 +924,33 @@ function (_PYTHON_VALIDATE_INTERPRETER) set_property (CACHE _${_PYTHON_PREFIX}_EXECUTABLE PROPERTY VALUE "${_PYTHON_PREFIX}_EXECUTABLE-NOTFOUND") return() endif() + + if (WIN32) + # In this case, check if the interpreter is compatible with the target processor architecture + if (NOT CMAKE_GENERATOR_PLATFORM AND CMAKE_SYSTEM_PROCESSOR MATCHES "ARM" OR CMAKE_GENERATOR_PLATFORM MATCHES "ARM") + set(target_arm TRUE) + else() + set(target_arm FALSE) + endif() + execute_process (COMMAND ${launcher} "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c + "import sys, sysconfig; sys.stdout.write(sysconfig.get_platform())" + RESULT_VARIABLE result + OUTPUT_VARIABLE platform + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) + string(TOUPPER "${platform}" platform) + if (result OR ((target_arm AND NOT platform MATCHES "ARM") OR + (NOT target_arm AND platform MATCHES "ARM"))) + # interpreter not usable or has wrong architecture + if (result) + set_property (CACHE _${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE PROPERTY VALUE "Cannot use the interpreter \"${_${_PYTHON_PREFIX}_EXECUTABLE}\"") + else() + set_property (CACHE _${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE PROPERTY VALUE "Wrong architecture for the interpreter \"${_${_PYTHON_PREFIX}_EXECUTABLE}\"") + endif() + set_property (CACHE _${_PYTHON_PREFIX}_EXECUTABLE PROPERTY VALUE "${_PYTHON_PREFIX}_EXECUTABLE-NOTFOUND") + return() + endif() + endif() endif() endfunction() @@ -1419,19 +1443,37 @@ if (CMAKE_SIZEOF_VOID_P) OR "Development.SABIModule" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS OR "Development.Embed" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS) # In this case, search only for 64bit or 32bit - set (_${_PYTHON_PREFIX}_ARCH2 ${_${_PYTHON_PREFIX}_ARCH}) set (_${_PYTHON_PREFIX}_REGISTRY_VIEW REGISTRY_VIEW ${_${_PYTHON_PREFIX}_ARCH}) + if (WIN32 AND (NOT CMAKE_GENERATOR_PLATFORM AND CMAKE_SYSTEM_PROCESSOR MATCHES "ARM" + OR CMAKE_GENERATOR_PLATFORM MATCHES "ARM")) + # search exclusively ARM architecture: 64bit or 32bit + if (_${_PYTHON_PREFIX}_ARCH EQUAL 64) + set (_${_PYTHON_PREFIX}_ARCH ARM64) + else() + set (_${_PYTHON_PREFIX}_ARCH ARM) + endif() + endif() else() if (_${_PYTHON_PREFIX}_ARCH EQUAL "32") - set (_${_PYTHON_PREFIX}_ARCH2 64) + if (CMAKE_SYSTEM_PROCESSOR MATCHES "ARM") + # search first ARM architectures: 32bit and then 64bit + list (PREPEND _${_PYTHON_PREFIX}_ARCH ARM ARM64) + endif() + list (APPEND _${_PYTHON_PREFIX}_ARCH 64) else() - set (_${_PYTHON_PREFIX}_ARCH2 32) + if (CMAKE_SYSTEM_PROCESSOR MATCHES "ARM") + # search first ARM architectures: 64bit and then 32bit + list (PREPEND _${_PYTHON_PREFIX}_ARCH ARM64 ARM) + endif() + list (APPEND _${_PYTHON_PREFIX}_ARCH 32) endif() endif() else() # architecture unknown, search for both 64bit and 32bit - set (_${_PYTHON_PREFIX}_ARCH 64) - set (_${_PYTHON_PREFIX}_ARCH2 32) + set (_${_PYTHON_PREFIX}_ARCH 64 32) + if (CMAKE_SYSTEM_PROCESSOR MATCHES "ARM") + list (PREPEND _${_PYTHON_PREFIX}_ARCH ARM64 ARM) + endif() endif() # IronPython support @@ -1439,7 +1481,7 @@ unset (_${_PYTHON_PREFIX}_IRON_PYTHON_INTERPRETER_NAMES) unset (_${_PYTHON_PREFIX}_IRON_PYTHON_COMPILER_NAMES) unset (_${_PYTHON_PREFIX}_IRON_PYTHON_COMPILER_ARCH_FLAGS) if (CMAKE_SIZEOF_VOID_P) - if (_${_PYTHON_PREFIX}_ARCH EQUAL "32") + if (CMAKE_SIZEOF_VOID_P EQUAL "4") set (_${_PYTHON_PREFIX}_IRON_PYTHON_COMPILER_ARCH_FLAGS "/platform:x86") else() set (_${_PYTHON_PREFIX}_IRON_PYTHON_COMPILER_ARCH_FLAGS "/platform:x64") @@ -2048,7 +2090,6 @@ if ("Interpreter" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS) list (GET _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES 3 ${_PYTHON_PREFIX}_VERSION_PATCH) list (GET _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES 4 _${_PYTHON_PREFIX}_ARCH) - set (_${_PYTHON_PREFIX}_ARCH2 ${_${_PYTHON_PREFIX}_ARCH}) list (GET _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES 5 _${_PYTHON_PREFIX}_ABIFLAGS) list (GET _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES 6 ${_PYTHON_PREFIX}_SOABI) @@ -2098,10 +2139,27 @@ if ("Interpreter" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS) if (NOT _${_PYTHON_PREFIX}_RESULT) if (${_PYTHON_PREFIX}_IS64BIT) set (_${_PYTHON_PREFIX}_ARCH 64) - set (_${_PYTHON_PREFIX}_ARCH2 64) else() set (_${_PYTHON_PREFIX}_ARCH 32) - set (_${_PYTHON_PREFIX}_ARCH2 32) + endif() + endif() + + if (WIN32) + # check if architecture is Intel or ARM + execute_process (COMMAND ${_${_PYTHON_PREFIX}_INTERPRETER_LAUNCHER} "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c + "import sys; import sysconfig; sys.stdout.write(sysconfig.get_platform())" + RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT + OUTPUT_VARIABLE _${_PYTHON_PREFIX}_PLATFORM + ERROR_VARIABLE ${_PYTHON_PREFIX}_PLATFORM) + if (NOT _${_PYTHON_PREFIX}_RESULT) + string(TOUPPER "${_${_PYTHON_PREFIX}_PLATFORM}" _${_PYTHON_PREFIX}_PLATFORM) + if (_${_PYTHON_PREFIX}_PLATFORM MATCHES "ARM") + if (${_PYTHON_PREFIX}_IS64BIT) + set (_${_PYTHON_PREFIX}_ARCH ARM64) + else() + set (_${_PYTHON_PREFIX}_ARCH ARM) + endif() + endif() endif() endif() endif() diff --git a/Modules/FindwxWidgets.cmake b/Modules/FindwxWidgets.cmake index 3159ff7..cc76b35 100644 --- a/Modules/FindwxWidgets.cmake +++ b/Modules/FindwxWidgets.cmake @@ -113,6 +113,16 @@ If wxWidgets is required (i.e., not an optional part): include(${wxWidgets_USE_FILE}) # and for each of your dependent executable/library targets: target_link_libraries(<YourTarget> ${wxWidgets_LIBRARIES}) + +Imported targets +^^^^^^^^^^^^^^^^ + +.. versionadded:: 3.27 + +This module defines the following :prop_tgt:`IMPORTED` targets: + +``wxWidgets::wxWidgets`` + An interface library providing usage requirements for the found components. #]=======================================================================] # @@ -981,6 +991,17 @@ find_package_handle_standard_args(wxWidgets ) unset(wxWidgets_HANDLE_COMPONENTS) +if(wxWidgets_FOUND AND NOT TARGET wxWidgets::wxWidgets) + add_library(wxWidgets::wxWidgets INTERFACE IMPORTED) + target_link_libraries(wxWidgets::wxWidgets INTERFACE ${wxWidgets_LIBRARIES}) + target_link_directories(wxWidgets::wxWidgets INTERFACE ${wxWidgets_LIBRARY_DIRS}) + target_include_directories(wxWidgets::wxWidgets INTERFACE ${wxWidgets_INCLUDE_DIRS}) + target_compile_options(wxWidgets::wxWidgets INTERFACE ${wxWidgets_CXX_FLAGS}) + target_compile_definitions(wxWidgets::wxWidgets INTERFACE ${wxWidgets_DEFINITIONS}) + # FIXME: Add "$<$<CONFIG:Debug>:${wxWidgets_DEFINITIONS_DEBUG}>" + # if the debug library variant is available. +endif() + #===================================================================== # Macros for use in wxWidgets apps. # - This module will not fail to find wxWidgets based on the code diff --git a/Modules/FortranCInterface/CMakeLists.txt b/Modules/FortranCInterface/CMakeLists.txt index 4bd7006..a0f1862 100644 --- a/Modules/FortranCInterface/CMakeLists.txt +++ b/Modules/FortranCInterface/CMakeLists.txt @@ -6,11 +6,11 @@ project(FortranCInterface C Fortran) include(${FortranCInterface_BINARY_DIR}/Input.cmake OPTIONAL) # Check if the C compiler supports '$' in identifiers. -include(CheckCSourceCompiles) -check_c_source_compiles(" -extern int dollar$(void); -int main() { return 0; } -" C_SUPPORTS_DOLLAR) +include(CheckSourceCompiles) +check_source_compiles(C +"extern int dollar$(void); +int main() { return 0; }" +C_SUPPORTS_DOLLAR) # List manglings of global symbol names to try. set(global_symbols diff --git a/Modules/GenerateExportHeader.cmake b/Modules/GenerateExportHeader.cmake index ea8616a..01a6e4f 100644 --- a/Modules/GenerateExportHeader.cmake +++ b/Modules/GenerateExportHeader.cmake @@ -198,19 +198,19 @@ that will be populated with the ``CXX_FLAGS`` required to enable visibility support for the compiler/architecture in use. #]=======================================================================] -include(CheckCCompilerFlag) -include(CheckCXXCompilerFlag) +include(CheckCompilerFlag) +include(CheckSourceCompiles) # TODO: Install this macro separately? macro(_check_cxx_compiler_attribute _ATTRIBUTE _RESULT) - check_cxx_source_compiles("${_ATTRIBUTE} int somefunc() { return 0; } + check_source_compiles(CXX "${_ATTRIBUTE} int somefunc() { return 0; } int main() { return somefunc();}" ${_RESULT} ) endmacro() # TODO: Install this macro separately? macro(_check_c_compiler_attribute _ATTRIBUTE _RESULT) - check_c_source_compiles("${_ATTRIBUTE} int somefunc() { return 0; } + check_source_compiles(C "${_ATTRIBUTE} int somefunc() { return 0; } int main() { return somefunc();}" ${_RESULT} ) endmacro() @@ -226,7 +226,7 @@ macro(_test_compiler_hidden_visibility) endif() # Exclude XL here because it misinterprets -fvisibility=hidden even though - # the check_cxx_compiler_flag passes + # the check_compiler_flag passes if(NOT GCC_TOO_OLD AND NOT _INTEL_TOO_OLD AND NOT WIN32 @@ -235,12 +235,12 @@ macro(_test_compiler_hidden_visibility) AND NOT CMAKE_CXX_COMPILER_ID MATCHES "^(PGI|NVHPC)$" AND NOT CMAKE_CXX_COMPILER_ID MATCHES Watcom) if (CMAKE_CXX_COMPILER_LOADED) - check_cxx_compiler_flag(-fvisibility=hidden COMPILER_HAS_HIDDEN_VISIBILITY) - check_cxx_compiler_flag(-fvisibility-inlines-hidden + check_compiler_flag(CXX -fvisibility=hidden COMPILER_HAS_HIDDEN_VISIBILITY) + check_compiler_flag(CXX -fvisibility-inlines-hidden COMPILER_HAS_HIDDEN_INLINE_VISIBILITY) else() - check_c_compiler_flag(-fvisibility=hidden COMPILER_HAS_HIDDEN_VISIBILITY) - check_c_compiler_flag(-fvisibility-inlines-hidden + check_compiler_flag(C -fvisibility=hidden COMPILER_HAS_HIDDEN_VISIBILITY) + check_compiler_flag(C -fvisibility-inlines-hidden COMPILER_HAS_HIDDEN_INLINE_VISIBILITY) endif() endif() diff --git a/Modules/Internal/CMakeTryCompilerOrLinkerFlag.cmake b/Modules/Internal/CMakeTryCompilerOrLinkerFlag.cmake index ff8908b..b671b4a 100644 --- a/Modules/Internal/CMakeTryCompilerOrLinkerFlag.cmake +++ b/Modules/Internal/CMakeTryCompilerOrLinkerFlag.cmake @@ -69,6 +69,7 @@ function(CMAKE_TRY_COMPILER_OR_LINKER_FLAG lang flag result) set (CCCF_COMMAND_PATTERN "<FLAG> -o <OUTPUT> <SOURCE>") endif() + list (APPEND CCCF_FAIL_REGEX "argument unused during compilation") # clang if (check_lang STREQUAL "C") list(APPEND CCCF_FAIL_REGEX "command line option .* is valid for .* but not for C") # GNU diff --git a/Modules/Internal/CheckFlagCommonConfig.cmake b/Modules/Internal/CheckFlagCommonConfig.cmake index 61eada2..8c5703d 100644 --- a/Modules/Internal/CheckFlagCommonConfig.cmake +++ b/Modules/Internal/CheckFlagCommonConfig.cmake @@ -7,7 +7,8 @@ # It's content may change in any way between releases. include_guard(GLOBAL) -cmake_policy(PUSH) + +block(SCOPE_FOR POLICIES) cmake_policy(SET CMP0054 NEW) # if() quoted variables not dereferenced cmake_policy(SET CMP0057 NEW) # if() supports IN_LIST @@ -22,26 +23,30 @@ macro(CMAKE_CHECK_FLAG_COMMON_INIT _FUNC _LANG _SRC _PATTERNS) FAIL_REGEX "-Werror=.* argument .* is not valid for C\\+\\+") elseif("${_LANG}" STREQUAL "CUDA") set(${_SRC} "__host__ int main() { return 0; }") - set(${_PATTERNS} FAIL_REGEX "command[ -]line option .* is valid for .* but not for C\\+\\+") # Host GNU + set(${_PATTERNS} FAIL_REGEX "command[ -]line option .* is valid for .* but not for C\\+\\+" # Host GNU + FAIL_REGEX "argument unused during compilation: .*") # Clang elseif("${_LANG}" STREQUAL "Fortran") set(${_SRC} " program test\n stop\n end program") set(${_PATTERNS} FAIL_REGEX "command[ -]line option .* is valid for .* but not for Fortran") elseif("${_LANG}" STREQUAL "HIP") set(${_SRC} "__host__ int main() { return 0; }") + set(${_PATTERNS} FAIL_REGEX "argument unused during compilation: .*") # Clang elseif("${_LANG}" STREQUAL "OBJC") set(${_SRC} [=[ #ifndef __OBJC__ # error "Not an Objective-C compiler" #endif int main(void) { return 0; }]=]) - set(${_PATTERNS} FAIL_REGEX "command[ -]line option .* is valid for .* but not for Objective-C") # GNU + set(${_PATTERNS} FAIL_REGEX "command[ -]line option .* is valid for .* but not for Objective-C" # GNU + FAIL_REGEX "argument unused during compilation: .*") # Clang elseif("${_LANG}" STREQUAL "OBJCXX") set(${_SRC} [=[ #ifndef __OBJC__ # error "Not an Objective-C++ compiler" #endif int main(void) { return 0; }]=]) - set(${_PATTERNS} FAIL_REGEX "command[ -]line option .* is valid for .* but not for Objective-C\\+\\+") # GNU + set(${_PATTERNS} FAIL_REGEX "command[ -]line option .* is valid for .* but not for Objective-C\\+\\+" # GNU + FAIL_REGEX "argument unused during compilation: .*") # Clang elseif("${_LANG}" STREQUAL "ISPC") set(${_SRC} "float func(uniform int32, float a) { return a / 2.25; }") elseif("${_LANG}" STREQUAL "Swift") @@ -70,4 +75,4 @@ macro(CMAKE_CHECK_FLAG_COMMON_FINISH) endforeach() endmacro() -cmake_policy(POP) +endblock() diff --git a/Modules/Internal/CheckLinkerFlag.cmake b/Modules/Internal/CheckLinkerFlag.cmake index 7613105..b872b51 100644 --- a/Modules/Internal/CheckLinkerFlag.cmake +++ b/Modules/Internal/CheckLinkerFlag.cmake @@ -6,7 +6,7 @@ include(Internal/CheckFlagCommonConfig) include(Internal/CheckSourceCompiles) include(CMakeCheckCompilerFlagCommonPatterns) -cmake_policy(PUSH) +block(SCOPE_FOR POLICIES) cmake_policy(SET CMP0054 NEW) # if() quoted variables not dereferenced function(CMAKE_CHECK_LINKER_FLAG _lang _flag _var) @@ -49,4 +49,4 @@ function(CMAKE_CHECK_LINKER_FLAG _lang _flag _var) cmake_check_flag_common_finish() endfunction() -cmake_policy(POP) +endblock() diff --git a/Modules/Internal/CheckSourceCompiles.cmake b/Modules/Internal/CheckSourceCompiles.cmake index 83d7020..14a9a61 100644 --- a/Modules/Internal/CheckSourceCompiles.cmake +++ b/Modules/Internal/CheckSourceCompiles.cmake @@ -3,7 +3,7 @@ include_guard(GLOBAL) -cmake_policy(PUSH) +block(SCOPE_FOR POLICIES) cmake_policy(SET CMP0054 NEW) # if() quoted variables not dereferenced cmake_policy(SET CMP0057 NEW) # if() supports IN_LIST @@ -131,4 +131,4 @@ function(CMAKE_CHECK_SOURCE_COMPILES _lang _source _var) endif() endfunction() -cmake_policy(POP) +endblock() diff --git a/Modules/Internal/CheckSourceRuns.cmake b/Modules/Internal/CheckSourceRuns.cmake index 805d98d..c01081e 100644 --- a/Modules/Internal/CheckSourceRuns.cmake +++ b/Modules/Internal/CheckSourceRuns.cmake @@ -3,7 +3,7 @@ include_guard(GLOBAL) -cmake_policy(PUSH) +block(SCOPE_FOR POLICIES) cmake_policy(SET CMP0054 NEW) # if() quoted variables not dereferenced cmake_policy(SET CMP0057 NEW) # if() supports IN_LIST @@ -124,4 +124,4 @@ function(CMAKE_CHECK_SOURCE_RUNS _lang _source _var) endif() endfunction() -cmake_policy(POP) +endblock() diff --git a/Modules/Internal/HeaderpadWorkaround.cmake b/Modules/Internal/HeaderpadWorkaround.cmake index 9a7f9f5..fccfaae 100644 --- a/Modules/Internal/HeaderpadWorkaround.cmake +++ b/Modules/Internal/HeaderpadWorkaround.cmake @@ -9,7 +9,7 @@ if(NOT APPLE) return() endif() -cmake_policy(PUSH) +block(SCOPE_FOR POLICIES) cmake_policy(SET CMP0054 NEW) # if() quoted variables not dereferenced function(__cmake_internal_workaround_headerpad_flag_conflict _LANG) @@ -66,4 +66,4 @@ endforeach() unset(__lang) unset(__enabled_languages) -cmake_policy(POP) +endblock() diff --git a/Modules/MatlabTestsRedirect.cmake b/Modules/MatlabTestsRedirect.cmake index d651cdd..8973231 100644 --- a/Modules/MatlabTestsRedirect.cmake +++ b/Modules/MatlabTestsRedirect.cmake @@ -19,8 +19,8 @@ # -P FindMatlab_TestsRedirect.cmake set(Matlab_UNIT_TESTS_CMD -nosplash -nodesktop -nodisplay ${Matlab_ADDITIONAL_STARTUP_OPTIONS}) -if(WIN32) - set(Matlab_UNIT_TESTS_CMD ${Matlab_UNIT_TESTS_CMD} -wait) +if(WIN32 AND maut_BATCH_OPTION STREQUAL "-r") + list(APPEND Matlab_UNIT_TESTS_CMD -wait) endif() if(NOT test_timeout) diff --git a/Modules/UseJava.cmake b/Modules/UseJava.cmake index 54a8cf7..99fd617 100644 --- a/Modules/UseJava.cmake +++ b/Modules/UseJava.cmake @@ -294,7 +294,7 @@ Header Generation .. deprecated:: 3.11 This command will no longer be supported starting with version 10 of the JDK - due to the `suppression of javah tool <https://openjdk.java.net/jeps/313>`_. + due to the `suppression of javah tool <https://openjdk.org/jeps/313>`_. The :ref:`add_jar(GENERATE_NATIVE_HEADERS) <add_jar>` command should be used instead. diff --git a/Modules/WriteBasicConfigVersionFile.cmake b/Modules/WriteBasicConfigVersionFile.cmake index 1c5ecd5..4db725c 100644 --- a/Modules/WriteBasicConfigVersionFile.cmake +++ b/Modules/WriteBasicConfigVersionFile.cmake @@ -49,7 +49,7 @@ function(WRITE_BASIC_CONFIG_VERSION_FILE _filename) if(NOT CVF_ARCH_INDEPENDENT) set(CVF_ARCH_INDEPENDENT_CHECK " # if the installed or the using project don't have CMAKE_SIZEOF_VOID_P set, ignore it: -if(CMAKE_SIZEOF_VOID_P STREQUAL \"\" OR \"${CMAKE_SIZEOF_VOID_P}\" STREQUAL \"\") +if(\"\${CMAKE_SIZEOF_VOID_P}\" STREQUAL \"\" OR \"${CMAKE_SIZEOF_VOID_P}\" STREQUAL \"\") return() endif() diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index e3c69e6..3ae0bc6 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -11,18 +11,6 @@ endif() include(CheckIncludeFile) -if(NOT CMake_DEFAULT_RECURSION_LIMIT) - if(DEFINED ENV{DASHBOARD_TEST_FROM_CTEST}) - set(CMake_DEFAULT_RECURSION_LIMIT 100) - elseif(MINGW OR MSYS) - set(CMake_DEFAULT_RECURSION_LIMIT 400) - elseif(WIN32 AND CMAKE_C_COMPILER_ID STREQUAL "IntelLLVM") - set(CMake_DEFAULT_RECURSION_LIMIT 600) - else() - set(CMake_DEFAULT_RECURSION_LIMIT 1000) - endif() -endif() - if(APPLE) set(CMake_USE_MACH_PARSER 1) endif() diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index d00115d..281a8a9 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -1,7 +1,7 @@ # CMake version number components. set(CMake_VERSION_MAJOR 3) set(CMake_VERSION_MINOR 26) -set(CMake_VERSION_PATCH 20230306) +set(CMake_VERSION_PATCH 20230330) #set(CMake_VERSION_RC 0) set(CMake_VERSION_IS_DIRTY 0) diff --git a/Source/cmBinUtilsWindowsPELinker.cxx b/Source/cmBinUtilsWindowsPELinker.cxx index 79e39e9..918f563 100644 --- a/Source/cmBinUtilsWindowsPELinker.cxx +++ b/Source/cmBinUtilsWindowsPELinker.cxx @@ -3,7 +3,10 @@ #include "cmBinUtilsWindowsPELinker.h" +#include <algorithm> +#include <iterator> #include <sstream> +#include <utility> #include <vector> #include <cm/memory> @@ -16,6 +19,27 @@ #ifdef _WIN32 # include <windows.h> + +# include "cmsys/Encoding.hxx" +#endif + +#ifdef _WIN32 +namespace { + +void ReplaceWithActualNameCasing(std::string& path) +{ + WIN32_FIND_DATAW findData; + HANDLE hFind = ::FindFirstFileW( + cmsys::Encoding::ToWindowsExtendedPath(path).c_str(), &findData); + + if (hFind != INVALID_HANDLE_VALUE) { + auto onDiskName = cmsys::Encoding::ToNarrow(findData.cFileName); + ::FindClose(hFind); + path.replace(path.end() - onDiskName.size(), path.end(), onDiskName); + } +} + +} #endif cmBinUtilsWindowsPELinker::cmBinUtilsWindowsPELinker( @@ -60,29 +84,47 @@ bool cmBinUtilsWindowsPELinker::ScanDependencies( if (!this->Tool->GetFileInfo(file, needed)) { return false; } - for (auto& n : needed) { - n = cmSystemTools::LowerCase(n); - } + + struct WinPEDependency + { + WinPEDependency(std::string o) + : Original(std::move(o)) + , LowerCase(cmSystemTools::LowerCase(Original)) + { + } + std::string const Original; + std::string const LowerCase; + }; + + std::vector<WinPEDependency> depends; + depends.reserve(needed.size()); + std::move(needed.begin(), needed.end(), std::back_inserter(depends)); std::string origin = cmSystemTools::GetFilenamePath(file); - for (auto const& lib : needed) { - if (!this->Archive->IsPreExcluded(lib)) { + for (auto const& lib : depends) { + if (!this->Archive->IsPreExcluded(lib.LowerCase)) { std::string path; bool resolved = false; - if (!this->ResolveDependency(lib, origin, path, resolved)) { + if (!this->ResolveDependency(lib.LowerCase, origin, path, resolved)) { return false; } if (resolved) { if (!this->Archive->IsPostExcluded(path)) { +#ifdef _WIN32 + ReplaceWithActualNameCasing(path); +#else + path.replace(path.end() - lib.Original.size(), path.end(), + lib.Original); +#endif bool unique; - this->Archive->AddResolvedPath(lib, path, unique); + this->Archive->AddResolvedPath(lib.Original, path, unique); if (unique && !this->ScanDependencies(path, cmStateEnums::SHARED_LIBRARY)) { return false; } } } else { - this->Archive->AddUnresolvedPath(lib); + this->Archive->AddUnresolvedPath(lib.Original); } } } diff --git a/Source/cmCommonTargetGenerator.cxx b/Source/cmCommonTargetGenerator.cxx index 5601bf2..f6fdd48 100644 --- a/Source/cmCommonTargetGenerator.cxx +++ b/Source/cmCommonTargetGenerator.cxx @@ -165,6 +165,7 @@ std::vector<std::string> cmCommonTargetGenerator::GetLinkedTargetDirectories( { std::vector<std::string> dirs; std::set<cmGeneratorTarget const*> emitted; + cmGlobalCommonGenerator* const gg = this->GlobalCommonGenerator; if (cmComputeLinkInformation* cli = this->GeneratorTarget->GetLinkInformation(config)) { cmComputeLinkInformation::ItemVector const& items = cli->GetItems(); @@ -172,6 +173,8 @@ std::vector<std::string> cmCommonTargetGenerator::GetLinkedTargetDirectories( cmGeneratorTarget const* linkee = item.Target; if (linkee && !linkee->IsImported() + // Skip targets that build after this one in a static lib cycle. + && gg->TargetOrderIndexLess(linkee, this->GeneratorTarget) // We can ignore the INTERFACE_LIBRARY items because // Target->GetLinkInformation already processed their // link interface and they don't have any output themselves. diff --git a/Source/cmComputeLinkInformation.cxx b/Source/cmComputeLinkInformation.cxx index 78508f3..a93477b 100644 --- a/Source/cmComputeLinkInformation.cxx +++ b/Source/cmComputeLinkInformation.cxx @@ -1563,7 +1563,7 @@ void cmComputeLinkInformation::AddTargetItem(LinkEntry const& entry) this->OldLinkDirItems.push_back(item.Value); } - if (target->IsFrameworkOnApple() && !this->GlobalGenerator->IsXcode()) { + if (target->IsFrameworkOnApple()) { // Add the framework directory and the framework item itself auto fwDescriptor = this->GlobalGenerator->SplitFrameworkPath( item.Value, cmGlobalGenerator::FrameworkFormat::Extended); @@ -1579,26 +1579,32 @@ void cmComputeLinkInformation::AddTargetItem(LinkEntry const& entry) // Add the directory portion to the framework search path. this->AddFrameworkPath(fwDescriptor->Directory); } - if (cmHasSuffix(entry.Feature, "FRAMEWORK"_s)) { - this->Items.emplace_back(fwDescriptor->GetLinkName(), ItemIsPath::Yes, - target, - this->FindLibraryFeature(entry.Feature)); - } else { + + if (this->GlobalGenerator->IsXcode()) { this->Items.emplace_back( item, ItemIsPath::Yes, target, - this->FindLibraryFeature( - entry.Feature == DEFAULT ? "__CMAKE_LINK_LIBRARY" : entry.Feature)); + this->FindLibraryFeature(entry.Feature == DEFAULT + ? "__CMAKE_LINK_FRAMEWORK" + : entry.Feature)); + } else { + if (cmHasSuffix(entry.Feature, "FRAMEWORK"_s)) { + this->Items.emplace_back(fwDescriptor->GetLinkName(), ItemIsPath::Yes, + target, + this->FindLibraryFeature(entry.Feature)); + } else { + this->Items.emplace_back( + item, ItemIsPath::Yes, target, + this->FindLibraryFeature(entry.Feature == DEFAULT + ? "__CMAKE_LINK_LIBRARY" + : entry.Feature)); + } } } else { // Now add the full path to the library. this->Items.emplace_back( item, ItemIsPath::Yes, target, this->FindLibraryFeature( - entry.Feature == DEFAULT - ? (target->IsFrameworkOnApple() && this->GlobalGenerator->IsXcode() - ? "__CMAKE_LINK_FRAMEWORK" - : "__CMAKE_LINK_LIBRARY") - : entry.Feature)); + entry.Feature == DEFAULT ? "__CMAKE_LINK_LIBRARY" : entry.Feature)); } } diff --git a/Source/cmConfigure.cmake.h.in b/Source/cmConfigure.cmake.h.in index 90f3de0..3f19a11 100644 --- a/Source/cmConfigure.cmake.h.in +++ b/Source/cmConfigure.cmake.h.in @@ -23,7 +23,7 @@ #cmakedefine CMake_USE_MACH_PARSER #cmakedefine CMake_USE_XCOFF_PARSER #cmakedefine CMAKE_USE_WMAKE -#define CMake_DEFAULT_RECURSION_LIMIT @CMake_DEFAULT_RECURSION_LIMIT@ +#cmakedefine CMake_DEFAULT_RECURSION_LIMIT @CMake_DEFAULT_RECURSION_LIMIT@ #define CMAKE_BIN_DIR "/@CMAKE_BIN_DIR@" #define CMAKE_DATA_DIR "/@CMAKE_DATA_DIR@" #define CMAKE_DOC_DIR "/@CMAKE_DOC_DIR@" diff --git a/Source/cmCxxModuleMapper.cxx b/Source/cmCxxModuleMapper.cxx index 7952dfc..59bf4c7 100644 --- a/Source/cmCxxModuleMapper.cxx +++ b/Source/cmCxxModuleMapper.cxx @@ -21,7 +21,7 @@ cm::optional<std::string> CxxModuleLocations::BmiGeneratorPathForModule( std::string const& logical_name) const { if (auto l = this->BmiLocationForModule(logical_name)) { - return this->PathForGenerator(*l); + return this->PathForGenerator(std::move(*l)); } return {}; } @@ -239,8 +239,7 @@ std::set<std::string> CxxModuleUsageSeed( for (auto const& p : object.Provides) { if (auto bmi_loc = loc.BmiGeneratorPathForModule(p.LogicalName)) { // XXX(cxx-modules): How to support header units? - usages.AddReference(p.LogicalName, loc.PathForGenerator(*bmi_loc), - LookupMethod::ByName); + usages.AddReference(p.LogicalName, *bmi_loc, LookupMethod::ByName); } } @@ -268,8 +267,7 @@ std::set<std::string> CxxModuleUsageSeed( } if (bmi_loc) { - usages.AddReference(r.LogicalName, loc.PathForGenerator(*bmi_loc), - r.Method); + usages.AddReference(r.LogicalName, *bmi_loc, r.Method); } } } diff --git a/Source/cmCxxModuleMapper.h b/Source/cmCxxModuleMapper.h index 9271978..0f453b0 100644 --- a/Source/cmCxxModuleMapper.h +++ b/Source/cmCxxModuleMapper.h @@ -30,7 +30,7 @@ struct CxxModuleLocations std::string RootDirectory; // A function to convert a full path to a path for the generator. - std::function<std::string(std::string const&)> PathForGenerator; + std::function<std::string(std::string)> PathForGenerator; // Lookup the BMI location of a logical module name. std::function<cm::optional<std::string>(std::string const&)> diff --git a/Source/cmDyndepCollation.cxx b/Source/cmDyndepCollation.cxx index 2827659..53a262b 100644 --- a/Source/cmDyndepCollation.cxx +++ b/Source/cmDyndepCollation.cxx @@ -441,20 +441,16 @@ bool cmDyndepCollation::WriteDyndepMetadata( auto fileset_info_itr = export_info.ObjectToFileSet.find(output_path); bool const has_provides = !object.Provides.empty(); if (fileset_info_itr == export_info.ObjectToFileSet.end()) { - // If it provides anything, it should have a `CXX_MODULES` or - // `CXX_MODULE_INTERNAL_PARTITIONS` type and be present. + // If it provides anything, it should have type `CXX_MODULES` + // and be present. if (has_provides) { // Take the first module provided to provide context. auto const& provides = object.Provides[0]; - char const* ok_types = "`CXX_MODULES`"; - if (provides.LogicalName.find(':') != std::string::npos) { - ok_types = "`CXX_MODULES` (or `CXX_MODULE_INTERNAL_PARTITIONS` if " - "it is not `export`ed)"; - } - cmSystemTools::Error(cmStrCat( - "Output ", object.PrimaryOutput, " provides the `", - provides.LogicalName, - "` module but it is not found in a `FILE_SET` of type ", ok_types)); + cmSystemTools::Error( + cmStrCat("Output ", object.PrimaryOutput, " provides the `", + provides.LogicalName, + "` module but it is not found in a `FILE_SET` of type " + "`CXX_MODULES`")); result = false; } @@ -474,38 +470,15 @@ bool cmDyndepCollation::WriteDyndepMetadata( result = false; continue; } - } else if (file_set.Type == "CXX_MODULE_INTERNAL_PARTITIONS"_s) { - if (!has_provides) { - cmSystemTools::Error( - cmStrCat("Source ", file_set.SourcePath, - " is of type `CXX_MODULE_INTERNAL_PARTITIONS` but does not " - "provide a module")); - result = false; - continue; - } - auto const& provides = object.Provides[0]; - if (provides.LogicalName.find(':') == std::string::npos) { - cmSystemTools::Error( - cmStrCat("Source ", file_set.SourcePath, - " is of type `CXX_MODULE_INTERNAL_PARTITIONS` but does not " - "provide a module partition")); - result = false; - continue; - } } else if (file_set.Type == "CXX_MODULE_HEADERS"_s) { // TODO. } else { if (has_provides) { auto const& provides = object.Provides[0]; - char const* ok_types = "`CXX_MODULES`"; - if (provides.LogicalName.find(':') != std::string::npos) { - ok_types = "`CXX_MODULES` (or `CXX_MODULE_INTERNAL_PARTITIONS` if " - "it is not `export`ed)"; - } - cmSystemTools::Error( - cmStrCat("Source ", file_set.SourcePath, " provides the `", - provides.LogicalName, "` C++ module but is of type `", - file_set.Type, "` module but must be of type ", ok_types)); + cmSystemTools::Error(cmStrCat( + "Source ", file_set.SourcePath, " provides the `", + provides.LogicalName, "` C++ module but is of type `", file_set.Type, + "` module but must be of type `CXX_MODULES`")); result = false; } diff --git a/Source/cmFileAPICodemodel.cxx b/Source/cmFileAPICodemodel.cxx index d3683d4..4a8716f 100644 --- a/Source/cmFileAPICodemodel.cxx +++ b/Source/cmFileAPICodemodel.cxx @@ -1355,8 +1355,8 @@ CompileData Target::BuildCompileData(cmSourceFile* sf) } // Add precompile headers compile options. - std::vector<std::string> architectures; - this->GT->GetAppleArchs(this->Config, architectures); + std::vector<std::string> architectures = + this->GT->GetAppleArchs(this->Config, fd.Language); if (architectures.empty()) { architectures.emplace_back(); } diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx index 00a68a8..45fba8b 100644 --- a/Source/cmFileCommand.cxx +++ b/Source/cmFileCommand.cxx @@ -30,7 +30,6 @@ #include "cmArgumentParser.h" #include "cmArgumentParserTypes.h" -#include "cmCMakePath.h" #include "cmCryptoHash.h" #include "cmELF.h" #include "cmExecutionStatus.h" @@ -1278,9 +1277,9 @@ bool HandleRealPathCommand(std::vector<std::string> const& args, } } - cmCMakePath path(input, cmCMakePath::auto_format); - path = path.Absolute(*arguments.BaseDirectory).Normal(); - auto realPath = cmSystemTools::GetRealPath(path.GenericString()); + auto realPath = + cmSystemTools::CollapseFullPath(input, *arguments.BaseDirectory); + realPath = cmSystemTools::GetRealPath(realPath); status.GetMakefile().AddDefinition(args[2], realPath); diff --git a/Source/cmFindPackageCommand.cxx b/Source/cmFindPackageCommand.cxx index 8acfe83..355ca58 100644 --- a/Source/cmFindPackageCommand.cxx +++ b/Source/cmFindPackageCommand.cxx @@ -456,6 +456,51 @@ int parseVersion(const std::string& version, unsigned int& major, } // anonymous namespace +class cmFindPackageCommand::FlushDebugBufferOnExit +{ + cmFindPackageCommand& Command; + +public: + FlushDebugBufferOnExit(cmFindPackageCommand& command) + : Command(command) + { + } + ~FlushDebugBufferOnExit() + { + if (!Command.DebugBuffer.empty()) { + Command.DebugMessage(Command.DebugBuffer); + } + } +}; + +class cmFindPackageCommand::PushPopRootPathStack +{ + cmFindPackageCommand& Command; + +public: + PushPopRootPathStack(cmFindPackageCommand& command) + : Command(command) + { + Command.PushFindPackageRootPathStack(); + } + ~PushPopRootPathStack() { Command.PopFindPackageRootPathStack(); } +}; + +class cmFindPackageCommand::SetRestoreFindDefinitions +{ + cmFindPackageCommand& Command; + +public: + SetRestoreFindDefinitions( + cmFindPackageCommand& command, const std::string& components, + const std::vector<std::pair<std::string, const char*>>& componentVarDefs) + : Command(command) + { + Command.SetModuleVariables(components, componentVarDefs); + } + ~SetRestoreFindDefinitions() { Command.RestoreFindDefinitions(); } +}; + cmFindPackageCommand::PathLabel cmFindPackageCommand::PathLabel::PackageRedirect("PACKAGE_REDIRECT"); cmFindPackageCommand::PathLabel cmFindPackageCommand::PathLabel::UserRegistry( @@ -502,6 +547,7 @@ cmFindPackageCommand::cmFindPackageCommand(cmExecutionStatus& status) this->DebugMode = false; this->AppendSearchPathGroups(); + this->DeprecatedFindModules["CUDA"] = cmPolicies::CMP0146; this->DeprecatedFindModules["Dart"] = cmPolicies::CMP0145; this->DeprecatedFindModules["Qt"] = cmPolicies::CMP0084; } @@ -976,9 +1022,26 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args) } } - this->PushFindPackageRootPathStack(); + // Limit package nesting depth well below the recursion depth limit because + // find_package nesting uses more stack space than normal recursion. + { + static std::size_t const findPackageDepthMinMax = 100; + std::size_t const findPackageDepthMax = std::max( + this->Makefile->GetRecursionDepthLimit() / 2, findPackageDepthMinMax); + std::size_t const findPackageDepth = + this->Makefile->FindPackageRootPathStack.size() + 1; + if (findPackageDepth > findPackageDepthMax) { + this->SetError(cmStrCat("maximum nesting depth of ", findPackageDepthMax, + " exceeded.")); + return false; + } + } - this->SetModuleVariables(components, componentVarDefs); + // RAII objects to ensure we leave this function with consistent state + FlushDebugBufferOnExit flushDebugBufferOnExit(*this); + PushPopRootPathStack pushPopRootPathStack(*this); + SetRestoreFindDefinitions setRestoreFindDefinitions(*this, components, + componentVarDefs); // See if we have been told to delegate to FetchContent or some other // redirected config package first. We have to check all names that @@ -1099,15 +1162,6 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args) this->AppendSuccessInformation(); - // Restore original state of "_FIND_" variables set in SetModuleVariables() - this->RestoreFindDefinitions(); - - this->PopFindPackageRootPathStack(); - - if (!this->DebugBuffer.empty()) { - this->DebugMessage(this->DebugBuffer); - } - return loadedPackage; } diff --git a/Source/cmFindPackageCommand.h b/Source/cmFindPackageCommand.h index 18684c9..653e15f 100644 --- a/Source/cmFindPackageCommand.h +++ b/Source/cmFindPackageCommand.h @@ -105,6 +105,8 @@ private: void AddFindDefinition(const std::string& var, cm::string_view value); void RestoreFindDefinitions(); + class SetRestoreFindDefinitions; + enum /*class*/ HandlePackageModeType { Module, @@ -127,6 +129,7 @@ private: void PushFindPackageRootPathStack(); void PopFindPackageRootPathStack(); + class PushPopRootPathStack; void ComputePrefixes(); void FillPrefixesPackageRedirect(); @@ -215,6 +218,8 @@ private: std::set<std::string> IgnoredPrefixPaths; std::string DebugBuffer; + class FlushDebugBufferOnExit; + /*! the selected sortOrder (None by default)*/ SortOrderType SortOrder = None; /*! the selected sortDirection (Asc by default)*/ diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index 54cd8ba..8a14eaf 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -3,6 +3,7 @@ #include "cmGeneratorTarget.h" #include <algorithm> +#include <array> #include <cassert> #include <cerrno> #include <cstddef> @@ -1011,12 +1012,27 @@ const std::string& cmGeneratorTarget::GetObjectName(cmSourceFile const* file) const char* cmGeneratorTarget::GetCustomObjectExtension() const { - static std::string extension; - const bool has_ptx_extension = - this->GetPropertyAsBool("CUDA_PTX_COMPILATION"); - if (has_ptx_extension) { - extension = ".ptx"; - return extension.c_str(); + struct compiler_mode + { + std::string variable; + std::string extension; + }; + static std::array<compiler_mode, 4> const modes{ + { { "CUDA_PTX_COMPILATION", ".ptx" }, + { "CUDA_CUBIN_COMPILATION", ".cubin" }, + { "CUDA_FATBIN_COMPILATION", ".fatbin" }, + { "CUDA_OPTIX_COMPILATION", ".optixir" } } + }; + + std::string const& compiler = + this->Makefile->GetSafeDefinition("CMAKE_CUDA_COMPILER_ID"); + if (!compiler.empty()) { + for (const auto& m : modes) { + const bool has_extension = this->GetPropertyAsBool(m.variable); + if (has_extension) { + return m.extension.c_str(); + } + } } return nullptr; } @@ -3432,11 +3448,12 @@ std::string cmGeneratorTarget::GetCompilePDBDirectory( return ""; } -void cmGeneratorTarget::GetAppleArchs(const std::string& config, - std::vector<std::string>& archVec) const +std::vector<std::string> cmGeneratorTarget::GetAppleArchs( + std::string const& config, cm::optional<std::string> lang) const { + std::vector<std::string> archVec; if (!this->IsApple()) { - return; + return archVec; } cmValue archs = nullptr; if (!config.empty()) { @@ -3450,9 +3467,15 @@ void cmGeneratorTarget::GetAppleArchs(const std::string& config, if (archs) { cmExpandList(*archs, archVec); } - if (archVec.empty()) { + if (archVec.empty() && + // Fall back to a default architecture if no compiler target is set. + (!lang || + this->Makefile + ->GetDefinition(cmStrCat("CMAKE_", *lang, "_COMPILER_TARGET")) + .IsEmpty())) { this->Makefile->GetDefExpandList("_CMAKE_APPLE_ARCHS_DEFAULT", archVec); } + return archVec; } void cmGeneratorTarget::AddExplicitLanguageFlags(std::string& flags, diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h index 5d26191..256ca3b 100644 --- a/Source/cmGeneratorTarget.h +++ b/Source/cmGeneratorTarget.h @@ -484,8 +484,8 @@ public: holding object files for the given configuration. */ std::string GetObjectDirectory(std::string const& config) const; - void GetAppleArchs(const std::string& config, - std::vector<std::string>& archVec) const; + std::vector<std::string> GetAppleArchs(std::string const& config, + cm::optional<std::string> lang) const; void AddExplicitLanguageFlags(std::string& flags, cmSourceFile const& sf) const; diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx index 72eed69..0e9f78e 100644 --- a/Source/cmGlobalGenerator.cxx +++ b/Source/cmGlobalGenerator.cxx @@ -110,8 +110,6 @@ cmGlobalGenerator::cmGlobalGenerator(cmake* cm) this->ConfigureDoneCMP0026AndCMP0024 = false; this->FirstTimeProgress = 0.0f; - this->RecursionDepth = 0; - cm->GetState()->SetIsGeneratorMultiConfig(false); cm->GetState()->SetMinGWMake(false); cm->GetState()->SetMSYSShell(false); @@ -1729,8 +1727,7 @@ cmGlobalGenerator::GetLocalGeneratorTargetsInOrder(cmLocalGenerator* lg) const cm::append(gts, lg->GetGeneratorTargets()); std::sort(gts.begin(), gts.end(), [this](cmGeneratorTarget const* l, cmGeneratorTarget const* r) { - return this->TargetOrderIndex.at(l) < - this->TargetOrderIndex.at(r); + return this->TargetOrderIndexLess(l, r); }); return gts; } @@ -3070,6 +3067,12 @@ cmGlobalGenerator::GetTargetDirectDepends(cmGeneratorTarget const* target) return this->TargetDependencies[target]; } +bool cmGlobalGenerator::TargetOrderIndexLess(cmGeneratorTarget const* l, + cmGeneratorTarget const* r) const +{ + return this->TargetOrderIndex.at(l) < this->TargetOrderIndex.at(r); +} + bool cmGlobalGenerator::IsReservedTarget(std::string const& name) { // The following is a list of targets reserved diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h index 66ab752..4d321b5 100644 --- a/Source/cmGlobalGenerator.h +++ b/Source/cmGlobalGenerator.h @@ -479,6 +479,11 @@ public: TargetDependSet const& GetTargetDirectDepends( const cmGeneratorTarget* target); + // Return true if target 'l' occurs before 'r' in a global ordering + // of targets that respects inter-target dependencies. + bool TargetOrderIndexLess(cmGeneratorTarget const* l, + cmGeneratorTarget const* r) const; + const std::map<std::string, std::vector<cmLocalGenerator*>>& GetProjectMap() const { @@ -586,7 +591,7 @@ public: std::string MakeSilentFlag; - int RecursionDepth; + size_t RecursionDepth = 0; virtual void GetQtAutoGenConfigs(std::vector<std::string>& configs) const { diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx index d29c086..0c28776 100644 --- a/Source/cmGlobalNinjaGenerator.cxx +++ b/Source/cmGlobalNinjaGenerator.cxx @@ -8,7 +8,6 @@ #include <cstdio> #include <functional> #include <sstream> -#include <tuple> #include <utility> #include <cm/iterator> @@ -64,6 +63,19 @@ std::string const cmGlobalNinjaGenerator::SHELL_NOOP = "cd ."; std::string const cmGlobalNinjaGenerator::SHELL_NOOP = ":"; #endif +namespace { +#ifdef _WIN32 +bool DetectGCCOnWindows(cm::string_view compilerId, cm::string_view simulateId, + cm::string_view compilerFrontendVariant) +{ + return ((compilerId == "Clang"_s && compilerFrontendVariant == "GNU"_s) || + (simulateId != "MSVC"_s && + (compilerId == "GNU"_s || compilerId == "QCC"_s || + cmHasLiteralSuffix(compilerId, "Clang")))); +} +#endif +} + bool operator==( const cmGlobalNinjaGenerator::ByConfig::TargetDependsClosureKey& lhs, const cmGlobalNinjaGenerator::ByConfig::TargetDependsClosureKey& rhs) @@ -580,7 +592,7 @@ void cmGlobalNinjaGenerator::Generate() } for (auto& it : this->Configs) { - it.second.TargetDependsClosureLocalOutputs.clear(); + it.second.TargetDependsClosures.clear(); } this->TargetAll = this->NinjaOutputPath("all"); @@ -937,11 +949,8 @@ void cmGlobalNinjaGenerator::EnableLanguage( mf->GetSafeDefinition(cmStrCat("CMAKE_", l, "_SIMULATE_ID")); std::string const& compilerFrontendVariant = mf->GetSafeDefinition( cmStrCat("CMAKE_", l, "_COMPILER_FRONTEND_VARIANT")); - if ((compilerId == "Clang" && compilerFrontendVariant == "GNU") || - (simulateId != "MSVC" && - (compilerId == "GNU" || compilerId == "QCC" || - cmHasLiteralSuffix(compilerId, "Clang")))) { - this->UsingGCCOnWindows = true; + if (DetectGCCOnWindows(compilerId, simulateId, compilerFrontendVariant)) { + this->MarkAsGCCOnWindows(); } #endif } @@ -1360,88 +1369,64 @@ void cmGlobalNinjaGenerator::AppendTargetDepends( } void cmGlobalNinjaGenerator::AppendTargetDependsClosure( - cmGeneratorTarget const* target, cmNinjaDeps& outputs, - const std::string& config, const std::string& fileConfig, bool genexOutput) + cmGeneratorTarget const* target, std::unordered_set<std::string>& outputs, + const std::string& config, const std::string& fileConfig, bool genexOutput, + bool omit_self) { - struct Entry - { - Entry(cmGeneratorTarget const* target_, std::string config_, - std::string fileConfig_) - : target(target_) - , config(std::move(config_)) - , fileConfig(std::move(fileConfig_)) - { - } - - bool operator<(Entry const& other) const - { - return std::tie(target, config, fileConfig) < - std::tie(other.target, other.config, other.fileConfig); - } - cmGeneratorTarget const* target; - std::string config; - std::string fileConfig; + // try to locate the target in the cache + ByConfig::TargetDependsClosureKey key{ + target, + config, + genexOutput, }; - - cmNinjaOuts outputSet; - std::vector<Entry> stack; - stack.emplace_back(target, config, fileConfig); - std::set<Entry> seen = { stack.back() }; - - do { - Entry entry = std::move(stack.back()); - stack.pop_back(); - - // generate the outputs of the target itself, if applicable - if (entry.target != target) { - // try to locate the target in the cache - ByConfig::TargetDependsClosureKey localCacheKey{ - entry.target, - entry.config, - genexOutput, - }; - auto& configs = this->Configs[entry.fileConfig]; - auto lb = - configs.TargetDependsClosureLocalOutputs.lower_bound(localCacheKey); - - if (lb == configs.TargetDependsClosureLocalOutputs.end() || - lb->first != localCacheKey) { - cmNinjaDeps outs; - this->AppendTargetOutputs(entry.target, outs, entry.config, - DependOnTargetArtifact); - configs.TargetDependsClosureLocalOutputs.emplace_hint( - lb, localCacheKey, outs); - for (auto& value : outs) { - outputSet.emplace(std::move(value)); - } - } else { - outputSet.insert(lb->second.begin(), lb->second.end()); - } - } - - // push next dependencies - for (const auto& dep_target : this->GetTargetDirectDepends(entry.target)) { + auto find = this->Configs[fileConfig].TargetDependsClosures.lower_bound(key); + + if (find == this->Configs[fileConfig].TargetDependsClosures.end() || + find->first != key) { + // We now calculate the closure outputs by inspecting the dependent + // targets recursively. + // For that we have to distinguish between a local result set that is only + // relevant for filling the cache entries properly isolated and a global + // result set that is relevant for the result of the top level call to + // AppendTargetDependsClosure. + std::unordered_set<std::string> + this_outs; // this will be the new cache entry + + for (auto const& dep_target : this->GetTargetDirectDepends(target)) { if (!dep_target->IsInBuildSystem()) { continue; } - if (!this->IsSingleConfigUtility(entry.target) && + if (!this->IsSingleConfigUtility(target) && !this->IsSingleConfigUtility(dep_target) && this->EnableCrossConfigBuild() && !dep_target.IsCross() && !genexOutput) { continue; } - auto emplaceRes = seen.emplace( - dep_target, dep_target.IsCross() ? entry.fileConfig : entry.config, - entry.fileConfig); - if (emplaceRes.second) { - stack.emplace_back(*emplaceRes.first); + if (dep_target.IsCross()) { + this->AppendTargetDependsClosure(dep_target, this_outs, fileConfig, + fileConfig, genexOutput, false); + } else { + this->AppendTargetDependsClosure(dep_target, this_outs, config, + fileConfig, genexOutput, false); } } - } while (!stack.empty()); - cm::append(outputs, outputSet); + find = this->Configs[fileConfig].TargetDependsClosures.emplace_hint( + find, key, std::move(this_outs)); + } + + // now fill the outputs of the final result from the newly generated cache + // entry + outputs.insert(find->second.begin(), find->second.end()); + + // finally generate the outputs of the target itself, if applicable + cmNinjaDeps outs; + if (!omit_self) { + this->AppendTargetOutputs(target, outs, config, DependOnTargetArtifact); + } + outputs.insert(outs.begin(), outs.end()); } void cmGlobalNinjaGenerator::AddTargetAlias(const std::string& alias, @@ -2645,8 +2630,14 @@ bool cmGlobalNinjaGenerator::WriteDyndepFile( { CxxModuleLocations locs; locs.RootDirectory = "."; - locs.PathForGenerator = [this](std::string const& path) -> std::string { - return this->ConvertToNinjaPath(path); + locs.PathForGenerator = [this](std::string path) -> std::string { + path = this->ConvertToNinjaPath(path); +# ifdef _WIN32 + if (this->IsGCCOnWindows()) { + std::replace(path.begin(), path.end(), '\\', '/'); + } +# endif + return path; }; locs.BmiLocationForModule = [&mod_files](std::string const& logical) -> cm::optional<std::string> { @@ -2827,6 +2818,10 @@ int cmcmd_cmake_ninja_dyndep(std::vector<std::string>::const_iterator argBeg, linked_target_dirs.push_back(tdi_linked_target_dir.asString()); } } + std::string const compilerId = tdi["compiler-id"].asString(); + std::string const simulateId = tdi["compiler-simulate-id"].asString(); + std::string const compilerFrontendVariant = + tdi["compiler-frontend-variant"].asString(); auto export_info = cmDyndepCollation::ParseExportInfo(tdi); @@ -2834,14 +2829,21 @@ int cmcmd_cmake_ninja_dyndep(std::vector<std::string>::const_iterator argBeg, cm.SetHomeDirectory(dir_top_src); cm.SetHomeOutputDirectory(dir_top_bld); auto ggd = cm.CreateGlobalGenerator("Ninja"); - if (!ggd || - !cm::static_reference_cast<cmGlobalNinjaGenerator>(ggd).WriteDyndepFile( - dir_top_src, dir_top_bld, dir_cur_src, dir_cur_bld, arg_dd, arg_ddis, - module_dir, linked_target_dirs, arg_lang, arg_modmapfmt, - *export_info)) { + if (!ggd) { return 1; } - return 0; + cmGlobalNinjaGenerator& gg = + cm::static_reference_cast<cmGlobalNinjaGenerator>(ggd); +# ifdef _WIN32 + if (DetectGCCOnWindows(compilerId, simulateId, compilerFrontendVariant)) { + gg.MarkAsGCCOnWindows(); + } +# endif + return gg.WriteDyndepFile(dir_top_src, dir_top_bld, dir_cur_src, dir_cur_bld, + arg_dd, arg_ddis, module_dir, linked_target_dirs, + arg_lang, arg_modmapfmt, *export_info) + ? 0 + : 1; } #endif diff --git a/Source/cmGlobalNinjaGenerator.h b/Source/cmGlobalNinjaGenerator.h index 6d23e89..bd54168 100644 --- a/Source/cmGlobalNinjaGenerator.h +++ b/Source/cmGlobalNinjaGenerator.h @@ -169,6 +169,7 @@ public: const std::string& comment = ""); bool IsGCCOnWindows() const { return this->UsingGCCOnWindows; } + void MarkAsGCCOnWindows() { this->UsingGCCOnWindows = true; } cmGlobalNinjaGenerator(cmake* cm); @@ -350,10 +351,10 @@ public: const std::string& fileConfig, cmNinjaTargetDepends depends); void AppendTargetDependsClosure(cmGeneratorTarget const* target, - cmNinjaDeps& outputs, + std::unordered_set<std::string>& outputs, const std::string& config, const std::string& fileConfig, - bool genexOutput); + bool genexOutput, bool omit_self = true); void AppendDirectoryForConfig(const std::string& prefix, const std::string& config, @@ -611,8 +612,8 @@ private: bool GenexOutput; }; - std::map<TargetDependsClosureKey, cmNinjaDeps> - TargetDependsClosureLocalOutputs; + std::map<TargetDependsClosureKey, std::unordered_set<std::string>> + TargetDependsClosures; TargetAliasMap TargetAliases; diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx index 5b3ac60..1396357 100644 --- a/Source/cmGlobalXCodeGenerator.cxx +++ b/Source/cmGlobalXCodeGenerator.cxx @@ -2513,8 +2513,8 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmGeneratorTarget* gtgt, } // Set target-specific architectures. - std::vector<std::string> archs; - gtgt->GetAppleArchs(configName, archs); + std::vector<std::string> archs = + gtgt->GetAppleArchs(configName, cm::nullopt); if (!archs.empty()) { // Enable ARCHS attribute. diff --git a/Source/cmIncludeCommand.cxx b/Source/cmIncludeCommand.cxx index 3564cf7..56883fb 100644 --- a/Source/cmIncludeCommand.cxx +++ b/Source/cmIncludeCommand.cxx @@ -22,6 +22,7 @@ bool cmIncludeCommand(std::vector<std::string> const& args, if (DeprecatedModules.empty()) { DeprecatedModules["Dart"] = cmPolicies::CMP0145; DeprecatedModules["Documentation"] = cmPolicies::CMP0106; + DeprecatedModules["FindCUDA"] = cmPolicies::CMP0146; DeprecatedModules["FindDart"] = cmPolicies::CMP0145; DeprecatedModules["WriteCompilerDetectionHeader"] = cmPolicies::CMP0120; } diff --git a/Source/cmInstallTargetGenerator.cxx b/Source/cmInstallTargetGenerator.cxx index 6c31da6..9220123 100644 --- a/Source/cmInstallTargetGenerator.cxx +++ b/Source/cmInstallTargetGenerator.cxx @@ -529,7 +529,7 @@ void cmInstallTargetGenerator::AddInstallNamePatchRule( std::ostream& os, Indent indent, const std::string& config, std::string const& toDestDirPath) { - if (this->ImportLibrary || + if (this->ImportLibrary || this->NamelinkMode == NamelinkModeOnly || !(this->Target->GetType() == cmStateEnums::SHARED_LIBRARY || this->Target->GetType() == cmStateEnums::MODULE_LIBRARY || this->Target->GetType() == cmStateEnums::EXECUTABLE)) { @@ -626,7 +626,8 @@ void cmInstallTargetGenerator::AddRPathCheckRule( std::string const& toDestDirPath) { // Skip the chrpath if the target does not need it. - if (this->ImportLibrary || !this->Target->IsChrpathUsed(config)) { + if (this->ImportLibrary || this->NamelinkMode == NamelinkModeOnly || + !this->Target->IsChrpathUsed(config)) { return; } // Skip if on Apple @@ -677,7 +678,8 @@ void cmInstallTargetGenerator::AddChrpathPatchRule( std::string const& toDestDirPath) { // Skip the chrpath if the target does not need it. - if (this->ImportLibrary || !this->Target->IsChrpathUsed(config)) { + if (this->ImportLibrary || this->NamelinkMode == NamelinkModeOnly || + !this->Target->IsChrpathUsed(config)) { return; } @@ -816,7 +818,7 @@ void cmInstallTargetGenerator::AddStripRule(std::ostream& os, Indent indent, // don't strip static and import libraries, because it removes the only // symbol table they have so you can't link to them anymore if (this->Target->GetType() == cmStateEnums::STATIC_LIBRARY || - this->ImportLibrary) { + this->ImportLibrary || this->NamelinkMode == NamelinkModeOnly) { return; } diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index bd7eb3f..01e4241 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -1873,8 +1873,7 @@ void cmLocalGenerator::AddArchitectureFlags(std::string& flags, { // Only add Apple specific flags on Apple platforms if (target->IsApple() && this->EmitUniversalBinaryFlags) { - std::vector<std::string> archs; - target->GetAppleArchs(config, archs); + std::vector<std::string> archs = target->GetAppleArchs(config, lang); if (!archs.empty() && (lang == "C" || lang == "CXX" || lang == "OBJC" || lang == "OBJCXX" || lang == "ASM")) { @@ -2594,7 +2593,7 @@ void cmLocalGenerator::AddPchDependencies(cmGeneratorTarget* target) std::vector<std::string> architectures; if (!this->GetGlobalGenerator()->IsXcode()) { - target->GetAppleArchs(config, architectures); + architectures = target->GetAppleArchs(config, lang); } if (architectures.empty()) { architectures.emplace_back(); diff --git a/Source/cmLocalNinjaGenerator.cxx b/Source/cmLocalNinjaGenerator.cxx index f8027c0..d0bd375 100644 --- a/Source/cmLocalNinjaGenerator.cxx +++ b/Source/cmLocalNinjaGenerator.cxx @@ -5,11 +5,11 @@ #include <algorithm> #include <cassert> #include <cstdio> -#include <iterator> #include <memory> #include <sstream> #include <utility> +#include <cm/unordered_set> #include <cmext/string_view> #include "cmsys/FStream.hxx" @@ -26,6 +26,7 @@ #include "cmMakefile.h" #include "cmMessageType.h" #include "cmNinjaTargetGenerator.h" +#include "cmNinjaTypes.h" #include "cmPolicies.h" #include "cmRulePlaceholderExpander.h" #include "cmSourceFile.h" @@ -456,6 +457,22 @@ std::string cmLocalNinjaGenerator::WriteCommandScript( return scriptPath; } +#ifdef _WIN32 +namespace { +bool RuleNeedsCMD(std::string const& cmd) +{ + std::vector<std::string> args; + cmSystemTools::ParseWindowsCommandLine(cmd.c_str(), args); + auto it = std::find_if(args.cbegin(), args.cend(), + [](std::string const& arg) -> bool { + // FIXME: Detect more windows shell operators. + return cmHasLiteralPrefix(arg, ">"); + }); + return it != args.cend(); +} +} +#endif + std::string cmLocalNinjaGenerator::BuildCommandLine( std::vector<std::string> const& cmdLines, std::string const& outputConfig, std::string const& commandConfig, std::string const& customStep, @@ -498,12 +515,13 @@ std::string cmLocalNinjaGenerator::BuildCommandLine( } std::ostringstream cmd; - for (auto li = cmdLines.begin(); li != cmdLines.end(); ++li) #ifdef _WIN32 - { + bool const needCMD = + cmdLines.size() > 1 || (customStep.empty() && RuleNeedsCMD(cmdLines[0])); + for (auto li = cmdLines.begin(); li != cmdLines.end(); ++li) { if (li != cmdLines.begin()) { cmd << " && "; - } else if (cmdLines.size() > 1) { + } else if (needCMD) { cmd << "cmd.exe /C \""; } // Put current cmdLine in brackets if it contains "||" because it has @@ -514,11 +532,11 @@ std::string cmLocalNinjaGenerator::BuildCommandLine( cmd << *li; } } - if (cmdLines.size() > 1) { + if (needCMD) { cmd << "\""; } #else - { + for (auto li = cmdLines.begin(); li != cmdLines.end(); ++li) { if (li != cmdLines.begin()) { cmd << " && "; } @@ -584,7 +602,7 @@ void cmLocalNinjaGenerator::WriteCustomCommandBuildStatement( continue; } - cmNinjaDeps orderOnlyDeps; + std::unordered_set<std::string> orderOnlyDeps; if (!cc->GetDependsExplicitOnly()) { // A custom command may appear on multiple targets. However, some build @@ -600,19 +618,15 @@ void cmLocalNinjaGenerator::WriteCustomCommandBuildStatement( assert(j != targets.end()); this->GetGlobalNinjaGenerator()->AppendTargetDependsClosure( *j, orderOnlyDeps, ccg.GetOutputConfig(), fileConfig, ccgs.size() > 1); - std::sort(orderOnlyDeps.begin(), orderOnlyDeps.end()); ++j; for (; j != targets.end(); ++j) { - std::vector<std::string> jDeps; - std::vector<std::string> depsIntersection; + std::unordered_set<std::string> jDeps; this->GetGlobalNinjaGenerator()->AppendTargetDependsClosure( *j, jDeps, ccg.GetOutputConfig(), fileConfig, ccgs.size() > 1); - std::sort(jDeps.begin(), jDeps.end()); - std::set_intersection(orderOnlyDeps.begin(), orderOnlyDeps.end(), - jDeps.begin(), jDeps.end(), - std::back_inserter(depsIntersection)); - orderOnlyDeps = depsIntersection; + cm::erase_if(orderOnlyDeps, [&jDeps](std::string const& dep) { + return jDeps.find(dep) == jDeps.end(); + }); } } @@ -641,13 +655,17 @@ void cmLocalNinjaGenerator::WriteCustomCommandBuildStatement( std::vector<std::string> cmdLines; this->AppendCustomCommandLines(ccg, cmdLines); + cmNinjaDeps sortedOrderOnlyDeps(orderOnlyDeps.begin(), + orderOnlyDeps.end()); + std::sort(sortedOrderOnlyDeps.begin(), sortedOrderOnlyDeps.end()); + if (cmdLines.empty()) { cmNinjaBuild build("phony"); build.Comment = cmStrCat("Phony custom command for ", mainOutput); build.Outputs = std::move(ccOutputs.ExplicitOuts); build.WorkDirOuts = std::move(ccOutputs.WorkDirOuts); build.ExplicitDeps = std::move(ninjaDeps); - build.OrderOnlyDeps = orderOnlyDeps; + build.OrderOnlyDeps = std::move(sortedOrderOnlyDeps); gg->WriteBuild(this->GetImplFileStream(fileConfig), build); } else { std::string customStep = cmSystemTools::GetFilenameName(mainOutput); @@ -693,7 +711,8 @@ void cmLocalNinjaGenerator::WriteCustomCommandBuildStatement( this->ConstructComment(ccg), comment, depfile, cc->GetJobPool(), cc->GetUsesTerminal(), /*restat*/ !symbolic || !byproducts.empty(), fileConfig, - std::move(ccOutputs), std::move(ninjaDeps), std::move(orderOnlyDeps)); + std::move(ccOutputs), std::move(ninjaDeps), + std::move(sortedOrderOnlyDeps)); } } } diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx index 6806a5b..239748d 100644 --- a/Source/cmLocalVisualStudio7Generator.cxx +++ b/Source/cmLocalVisualStudio7Generator.cxx @@ -270,6 +270,7 @@ cmSourceFile* cmLocalVisualStudio7Generator::CreateVCProjBuildRule() cc->SetComment(comment.c_str()); cc->SetEscapeOldStyle(false); cc->SetStdPipesUTF8(true); + cc->SetUsesTerminal(true); this->AddCustomCommandToOutput(std::move(cc), true); if (cmSourceFile* file = this->Makefile->GetSource(makefileIn)) { // Finalize the source file path now since we're adding this after diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index 33843e2..fc82c14 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -67,6 +67,24 @@ # include "cmVariableWatch.h" #endif +#ifndef __has_feature +# define __has_feature(x) 0 +#endif + +// Select a recursion limit that fits within the stack size. +// See stack size flags in '../CompileFlags.cmake'. +#ifndef CMake_DEFAULT_RECURSION_LIMIT +# if __has_feature(address_sanitizer) +# define CMake_DEFAULT_RECURSION_LIMIT 400 +# elif defined(_MSC_VER) && defined(_DEBUG) +# define CMake_DEFAULT_RECURSION_LIMIT 600 +# elif defined(__ibmxl__) && defined(__linux) +# define CMake_DEFAULT_RECURSION_LIMIT 600 +# else +# define CMake_DEFAULT_RECURSION_LIMIT 1000 +# endif +#endif + class cmMessenger; cmDirectoryId::cmDirectoryId(std::string s) @@ -99,7 +117,6 @@ cmMakefile::cmMakefile(cmGlobalGenerator* globalGenerator, this->StateSnapshot = this->StateSnapshot.GetState()->CreatePolicyScopeSnapshot( this->StateSnapshot); - this->RecursionDepth = 0; // Enter a policy level for this directory. this->PushPolicy(); @@ -454,18 +471,10 @@ bool cmMakefile::ExecuteCommand(const cmListFileFunction& lff, static_cast<void>(stack_manager); // Check for maximum recursion depth. - int depth = CMake_DEFAULT_RECURSION_LIMIT; - cmValue depthStr = this->GetDefinition("CMAKE_MAXIMUM_RECURSION_DEPTH"); - if (depthStr) { - std::istringstream s(*depthStr); - int d; - if (s >> d) { - depth = d; - } - } - if (this->RecursionDepth > depth) { + size_t depthLimit = this->GetRecursionDepthLimit(); + if (this->RecursionDepth > depthLimit) { std::ostringstream e; - e << "Maximum recursion depth of " << depth << " exceeded"; + e << "Maximum recursion depth of " << depthLimit << " exceeded"; this->IssueMessage(MessageType::FATAL_ERROR, e.str()); cmSystemTools::SetFatalErrorOccurred(); return false; @@ -1229,7 +1238,7 @@ void cmMakefile::AddCustomCommandOldStyle( // Each output must get its own copy of this rule. cmsys::RegularExpression sourceFiles( - "\\.(C|M|c|c\\+\\+|cc|cpp|cxx|mpp|ixx|cppm|cu|m|mm|" + "\\.(C|M|c|c\\+\\+|cc|cpp|cxx|mpp|ixx|cppm|ccm|cxxm|c\\+\\+m|cu|m|mm|" "rc|def|r|odl|idl|hpj|bat|h|h\\+\\+|" "hm|hpp|hxx|in|txx|inl)$"); @@ -2865,12 +2874,31 @@ bool cmMakefile::IsProjectFile(const char* filename) const !cmSystemTools::IsSubDirectory(filename, "/CMakeFiles")); } -int cmMakefile::GetRecursionDepth() const +size_t cmMakefile::GetRecursionDepthLimit() const +{ + size_t depth = CMake_DEFAULT_RECURSION_LIMIT; + if (cmValue depthStr = + this->GetDefinition("CMAKE_MAXIMUM_RECURSION_DEPTH")) { + unsigned long depthUL; + if (cmStrToULong(depthStr.GetCStr(), &depthUL)) { + depth = depthUL; + } + } else if (cm::optional<std::string> depthEnv = + cmSystemTools::GetEnvVar("CMAKE_MAXIMUM_RECURSION_DEPTH")) { + unsigned long depthUL; + if (cmStrToULong(*depthEnv, &depthUL)) { + depth = depthUL; + } + } + return depth; +} + +size_t cmMakefile::GetRecursionDepth() const { return this->RecursionDepth; } -void cmMakefile::SetRecursionDepth(int recursionDepth) +void cmMakefile::SetRecursionDepth(size_t recursionDepth) { this->RecursionDepth = recursionDepth; } diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h index 6f04937..a43ff41 100644 --- a/Source/cmMakefile.h +++ b/Source/cmMakefile.h @@ -1023,8 +1023,10 @@ public: const char* sourceFilename) const; bool IsProjectFile(const char* filename) const; - int GetRecursionDepth() const; - void SetRecursionDepth(int recursionDepth); + size_t GetRecursionDepthLimit() const; + + size_t GetRecursionDepth() const; + void SetRecursionDepth(size_t recursionDepth); std::string NewDeferId() const; bool DeferCall(std::string id, std::string fileName, cmListFileFunction lff); @@ -1090,7 +1092,7 @@ protected: private: cmStateSnapshot StateSnapshot; cmListFileBacktrace Backtrace; - int RecursionDepth; + size_t RecursionDepth = 0; struct DeferCommand { diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index e217dd9..3112acd 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -3,6 +3,7 @@ #include "cmMakefileTargetGenerator.h" #include <algorithm> +#include <array> #include <cassert> #include <cstdio> #include <iterator> @@ -540,8 +541,8 @@ void cmMakefileTargetGenerator::WriteTargetLanguageFlags() *this->FlagFileStream << language << "_DEFINES = " << defines << "\n\n"; *this->FlagFileStream << language << "_INCLUDES = " << includes << "\n\n"; - std::vector<std::string> architectures; - this->GeneratorTarget->GetAppleArchs(this->GetConfigName(), architectures); + std::vector<std::string> architectures = + this->GeneratorTarget->GetAppleArchs(this->GetConfigName(), language); architectures.emplace_back(); for (const std::string& arch : architectures) { @@ -670,8 +671,8 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles( std::string configUpper = cmSystemTools::UpperCase(config); // Add precompile headers dependencies - std::vector<std::string> architectures; - this->GeneratorTarget->GetAppleArchs(config, architectures); + std::vector<std::string> architectures = + this->GeneratorTarget->GetAppleArchs(config, lang); if (architectures.empty()) { architectures.emplace_back(); } @@ -977,11 +978,23 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles( this->Makefile->GetRequiredDefinition("_CMAKE_CUDA_RDC_FLAG"); cudaCompileMode = cmStrCat(cudaCompileMode, rdcFlag, " "); } - if (this->GeneratorTarget->GetPropertyAsBool("CUDA_PTX_COMPILATION")) { - const std::string& ptxFlag = - this->Makefile->GetRequiredDefinition("_CMAKE_CUDA_PTX_FLAG"); - cudaCompileMode = cmStrCat(cudaCompileMode, ptxFlag); - } else { + + static std::array<cm::string_view, 4> const compileModes{ + { "PTX"_s, "CUBIN"_s, "FATBIN"_s, "OPTIX"_s } + }; + bool useNormalCompileMode = true; + for (cm::string_view mode : compileModes) { + auto propName = cmStrCat("CUDA_", mode, "_COMPILATION"); + auto defName = cmStrCat("_CMAKE_CUDA_", mode, "_FLAG"); + if (this->GeneratorTarget->GetPropertyAsBool(propName)) { + const std::string& flag = + this->Makefile->GetRequiredDefinition(defName); + cudaCompileMode = cmStrCat(cudaCompileMode, flag); + useNormalCompileMode = false; + break; + } + } + if (useNormalCompileMode) { const std::string& wholeFlag = this->Makefile->GetRequiredDefinition("_CMAKE_CUDA_WHOLE_FLAG"); cudaCompileMode = cmStrCat(cudaCompileMode, wholeFlag); @@ -1054,18 +1067,51 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles( // Maybe insert an include-what-you-use runner. if (!compileCommands.empty() && (lang == "C" || lang == "CXX" || lang == "OBJC" || lang == "OBJCXX")) { - std::string const tidy_prop = lang + "_CLANG_TIDY"; - cmValue tidy = this->GeneratorTarget->GetProperty(tidy_prop); + cmValue tidy = nullptr; cmValue iwyu = nullptr; cmValue cpplint = nullptr; cmValue cppcheck = nullptr; + std::string evaluatedTIDY; + std::string evaluatedIWYU; + std::string evaluatedCPPlint; + std::string evaluatedCPPcheck; + + std::string const tidy_prop = cmStrCat(lang, "_CLANG_TIDY"); + tidy = this->GeneratorTarget->GetProperty(tidy_prop); + evaluatedTIDY = cmGeneratorExpression::Evaluate( + *tidy, this->LocalGenerator, config, this->GeneratorTarget, nullptr, + this->GeneratorTarget, lang); + if (!evaluatedTIDY.empty()) { + tidy = cmValue(&evaluatedTIDY); + } + if (lang == "C" || lang == "CXX") { - std::string const iwyu_prop = lang + "_INCLUDE_WHAT_YOU_USE"; + std::string const iwyu_prop = cmStrCat(lang, "_INCLUDE_WHAT_YOU_USE"); iwyu = this->GeneratorTarget->GetProperty(iwyu_prop); - std::string const cpplint_prop = lang + "_CPPLINT"; + evaluatedIWYU = cmGeneratorExpression::Evaluate( + *iwyu, this->LocalGenerator, config, this->GeneratorTarget, nullptr, + this->GeneratorTarget, lang); + if (!evaluatedIWYU.empty()) { + iwyu = cmValue(&evaluatedIWYU); + } + + std::string const cpplint_prop = cmStrCat(lang, "_CPPLINT"); cpplint = this->GeneratorTarget->GetProperty(cpplint_prop); - std::string const cppcheck_prop = lang + "_CPPCHECK"; + evaluatedCPPlint = cmGeneratorExpression::Evaluate( + *cpplint, this->LocalGenerator, config, this->GeneratorTarget, + nullptr, this->GeneratorTarget, lang); + if (!evaluatedCPPlint.empty()) { + cpplint = cmValue(&evaluatedCPPlint); + } + + std::string const cppcheck_prop = cmStrCat(lang, "_CPPCHECK"); cppcheck = this->GeneratorTarget->GetProperty(cppcheck_prop); + evaluatedCPPcheck = cmGeneratorExpression::Evaluate( + *cppcheck, this->LocalGenerator, config, this->GeneratorTarget, + nullptr, this->GeneratorTarget, lang); + if (!evaluatedCPPcheck.empty()) { + cppcheck = cmValue(&evaluatedCPPcheck); + } } if (cmNonempty(iwyu) || cmNonempty(tidy) || cmNonempty(cpplint) || cmNonempty(cppcheck)) { diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx index 8663f46..e163edb 100644 --- a/Source/cmNinjaTargetGenerator.cxx +++ b/Source/cmNinjaTargetGenerator.cxx @@ -3,6 +3,7 @@ #include "cmNinjaTargetGenerator.h" #include <algorithm> +#include <array> #include <cassert> #include <functional> #include <iterator> @@ -168,9 +169,9 @@ std::string cmNinjaTargetGenerator::ComputeFlagsForObject( cmSourceFile const* source, const std::string& language, const std::string& config) { - std::vector<std::string> architectures; std::unordered_map<std::string, std::string> pchSources; - this->GeneratorTarget->GetAppleArchs(config, architectures); + std::vector<std::string> architectures = + this->GeneratorTarget->GetAppleArchs(config, language); if (architectures.empty()) { architectures.emplace_back(); } @@ -859,11 +860,22 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang, this->Makefile->GetRequiredDefinition("_CMAKE_CUDA_RDC_FLAG"); cudaCompileMode = cmStrCat(cudaCompileMode, rdcFlag, " "); } - if (this->GeneratorTarget->GetPropertyAsBool("CUDA_PTX_COMPILATION")) { - const std::string& ptxFlag = - this->Makefile->GetRequiredDefinition("_CMAKE_CUDA_PTX_FLAG"); - cudaCompileMode = cmStrCat(cudaCompileMode, ptxFlag); - } else { + static std::array<cm::string_view, 4> const compileModes{ + { "PTX"_s, "CUBIN"_s, "FATBIN"_s, "OPTIX"_s } + }; + bool useNormalCompileMode = true; + for (cm::string_view mode : compileModes) { + auto propName = cmStrCat("CUDA_", mode, "_COMPILATION"); + auto defName = cmStrCat("_CMAKE_CUDA_", mode, "_FLAG"); + if (this->GeneratorTarget->GetPropertyAsBool(propName)) { + const std::string& flag = + this->Makefile->GetRequiredDefinition(defName); + cudaCompileMode = cmStrCat(cudaCompileMode, flag); + useNormalCompileMode = false; + break; + } + } + if (useNormalCompileMode) { const std::string& wholeFlag = this->Makefile->GetRequiredDefinition("_CMAKE_CUDA_WHOLE_FLAG"); cudaCompileMode = cmStrCat(cudaCompileMode, wholeFlag); @@ -896,18 +908,51 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang, // Maybe insert an include-what-you-use runner. if (!compileCmds.empty() && (lang == "C" || lang == "CXX" || lang == "OBJC" || lang == "OBJCXX")) { - std::string const tidy_prop = cmStrCat(lang, "_CLANG_TIDY"); - cmValue tidy = this->GeneratorTarget->GetProperty(tidy_prop); + cmValue tidy = nullptr; cmValue iwyu = nullptr; cmValue cpplint = nullptr; cmValue cppcheck = nullptr; + std::string evaluatedTIDY; + std::string evaluatedIWYU; + std::string evaluatedCPPlint; + std::string evaluatedCPPcheck; + + std::string const tidy_prop = cmStrCat(lang, "_CLANG_TIDY"); + tidy = this->GeneratorTarget->GetProperty(tidy_prop); + evaluatedTIDY = cmGeneratorExpression::Evaluate( + *tidy, this->LocalGenerator, config, this->GeneratorTarget, nullptr, + this->GeneratorTarget, lang); + if (!evaluatedTIDY.empty()) { + tidy = cmValue(&evaluatedTIDY); + } + if (lang == "C" || lang == "CXX") { std::string const iwyu_prop = cmStrCat(lang, "_INCLUDE_WHAT_YOU_USE"); iwyu = this->GeneratorTarget->GetProperty(iwyu_prop); + evaluatedIWYU = cmGeneratorExpression::Evaluate( + *iwyu, this->LocalGenerator, config, this->GeneratorTarget, nullptr, + this->GeneratorTarget, lang); + if (!evaluatedIWYU.empty()) { + iwyu = cmValue(&evaluatedIWYU); + } + std::string const cpplint_prop = cmStrCat(lang, "_CPPLINT"); cpplint = this->GeneratorTarget->GetProperty(cpplint_prop); + evaluatedCPPlint = cmGeneratorExpression::Evaluate( + *cpplint, this->LocalGenerator, config, this->GeneratorTarget, nullptr, + this->GeneratorTarget, lang); + if (!evaluatedCPPlint.empty()) { + cpplint = cmValue(&evaluatedCPPlint); + } + std::string const cppcheck_prop = cmStrCat(lang, "_CPPCHECK"); cppcheck = this->GeneratorTarget->GetProperty(cppcheck_prop); + evaluatedCPPcheck = cmGeneratorExpression::Evaluate( + *cppcheck, this->LocalGenerator, config, this->GeneratorTarget, + nullptr, this->GeneratorTarget, lang); + if (!evaluatedCPPcheck.empty()) { + cppcheck = cmValue(&evaluatedCPPcheck); + } } if (cmNonempty(iwyu) || cmNonempty(tidy) || cmNonempty(cpplint) || cmNonempty(cppcheck)) { @@ -1378,8 +1423,8 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement( // Add precompile headers dependencies std::vector<std::string> depList; - std::vector<std::string> architectures; - this->GeneratorTarget->GetAppleArchs(config, architectures); + std::vector<std::string> architectures = + this->GeneratorTarget->GetAppleArchs(config, language); if (architectures.empty()) { architectures.emplace_back(); } @@ -1639,6 +1684,10 @@ void cmNinjaTargetGenerator::WriteTargetDependInfo(std::string const& lang, tdi["language"] = lang; tdi["compiler-id"] = this->Makefile->GetSafeDefinition( cmStrCat("CMAKE_", lang, "_COMPILER_ID")); + tdi["compiler-simulate-id"] = this->Makefile->GetSafeDefinition( + cmStrCat("CMAKE_", lang, "_SIMULATE_ID")); + tdi["compiler-frontend-variant"] = this->Makefile->GetSafeDefinition( + cmStrCat("CMAKE_", lang, "_COMPILER_FRONTEND_VARIANT")); std::string mod_dir; if (lang == "Fortran") { @@ -1789,11 +1838,22 @@ void cmNinjaTargetGenerator::ExportObjectCompileCommand( this->Makefile->GetRequiredDefinition("_CMAKE_CUDA_RDC_FLAG"); cudaCompileMode = cmStrCat(cudaCompileMode, rdcFlag, " "); } - if (this->GeneratorTarget->GetPropertyAsBool("CUDA_PTX_COMPILATION")) { - const std::string& ptxFlag = - this->Makefile->GetRequiredDefinition("_CMAKE_CUDA_PTX_FLAG"); - cudaCompileMode = cmStrCat(cudaCompileMode, ptxFlag); - } else { + static std::array<cm::string_view, 4> const compileModes{ + { "PTX"_s, "CUBIN"_s, "FATBIN"_s, "OPTIX"_s } + }; + bool useNormalCompileMode = true; + for (cm::string_view mode : compileModes) { + auto propName = cmStrCat("CUDA_", mode, "_COMPILATION"); + auto defName = cmStrCat("_CMAKE_CUDA_", mode, "_FLAG"); + if (this->GeneratorTarget->GetPropertyAsBool(propName)) { + const std::string& flag = + this->Makefile->GetRequiredDefinition(defName); + cudaCompileMode = cmStrCat(cudaCompileMode, flag); + useNormalCompileMode = false; + break; + } + } + if (useNormalCompileMode) { const std::string& wholeFlag = this->Makefile->GetRequiredDefinition("_CMAKE_CUDA_WHOLE_FLAG"); cudaCompileMode = cmStrCat(cudaCompileMode, wholeFlag); diff --git a/Source/cmNinjaTypes.h b/Source/cmNinjaTypes.h index c8a411e..b77e0b5 100644 --- a/Source/cmNinjaTypes.h +++ b/Source/cmNinjaTypes.h @@ -5,8 +5,8 @@ #include "cmConfigure.h" // IWYU pragma: keep #include <map> -#include <set> #include <string> +#include <unordered_set> #include <utility> #include <vector> @@ -17,7 +17,6 @@ enum cmNinjaTargetDepends }; using cmNinjaDeps = std::vector<std::string>; -using cmNinjaOuts = std::set<std::string>; using cmNinjaVars = std::map<std::string, std::string>; class cmNinjaRule diff --git a/Source/cmPolicies.h b/Source/cmPolicies.h index 830e14b..52993b8 100644 --- a/Source/cmPolicies.h +++ b/Source/cmPolicies.h @@ -439,6 +439,11 @@ class cmMakefile; "find_package uses upper-case <PACKAGENAME>_ROOT variables.", 3, 27, \ 0, cmPolicies::WARN) \ SELECT(POLICY, CMP0145, "The Dart and FindDart modules are removed.", 3, \ + 27, 0, cmPolicies::WARN) \ + SELECT(POLICY, CMP0146, "The FindCUDA module is removed.", 3, 27, 0, \ + cmPolicies::WARN) \ + SELECT(POLICY, CMP0147, \ + "Visual Studio generators build custom commands in parallel.", 3, \ 27, 0, cmPolicies::WARN) #define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1) @@ -479,7 +484,9 @@ class cmMakefile; F(CMP0131) \ F(CMP0142) -#define CM_FOR_EACH_CUSTOM_COMMAND_POLICY(F) F(CMP0116) +#define CM_FOR_EACH_CUSTOM_COMMAND_POLICY(F) \ + F(CMP0116) \ + F(CMP0147) /** \class cmPolicies * \brief Handles changes in CMake behavior and policies diff --git a/Source/cmQtAutoGenInitializer.cxx b/Source/cmQtAutoGenInitializer.cxx index 410330a..667e0f5 100644 --- a/Source/cmQtAutoGenInitializer.cxx +++ b/Source/cmQtAutoGenInitializer.cxx @@ -5,6 +5,7 @@ #include <cstddef> #include <deque> #include <initializer_list> +#include <limits> #include <map> #include <set> #include <sstream> // for basic_ios, istringstream @@ -457,12 +458,23 @@ bool cmQtAutoGenInitializer::InitCustomTargets() // Autogen target parallel processing { + using ParallelType = decltype(this->AutogenTarget.Parallel); + unsigned long propInt = 0; std::string const& prop = this->GenTarget->GetSafeProperty("AUTOGEN_PARALLEL"); if (prop.empty() || (prop == "AUTO")) { // Autodetect number of CPUs this->AutogenTarget.Parallel = GetParallelCPUCount(); + } else if (cmStrToULong(prop, &propInt) && propInt > 0 && + propInt <= std::numeric_limits<ParallelType>::max()) { + this->AutogenTarget.Parallel = static_cast<ParallelType>(propInt); } else { + // Warn the project author that AUTOGEN_PARALLEL is not valid. + this->Makefile->IssueMessage( + MessageType::AUTHOR_WARNING, + cmStrCat("AUTOGEN_PARALLEL=\"", prop, "\" for target \"", + this->GenTarget->GetName(), + "\" is not valid. Using AUTOGEN_PARALLEL=1")); this->AutogenTarget.Parallel = 1; } } diff --git a/Source/cmRST.cxx b/Source/cmRST.cxx index fa9d4cc..f48330d 100644 --- a/Source/cmRST.cxx +++ b/Source/cmRST.cxx @@ -20,8 +20,8 @@ cmRST::cmRST(std::ostream& os, std::string docroot) : OS(os) , DocRoot(std::move(docroot)) , CMakeDirective("^.. (cmake:)?(" - "command|envvar|genex|variable" - ")::[ \t]+([^ \t\n]+)$") + "command|envvar|genex|signature|variable" + ")::") , CMakeModuleDirective("^.. cmake-module::[ \t]+([^ \t\n]+)$") , ParsedLiteralDirective("^.. parsed-literal::[ \t]*(.*)$") , CodeBlockDirective("^.. code-block::[ \t]*(.*)$") @@ -33,6 +33,7 @@ cmRST::cmRST(std::ostream& os, std::string docroot) , VersionDirective("^.. version(added|changed)::[ \t]*(.*)$") , ModuleRST(R"(^#\[(=*)\[\.rst:$)") , CMakeRole("(:cmake)?:(" + "cref|" "command|cpack_gen|generator|genex|" "variable|envvar|module|policy|" "prop_cache|prop_dir|prop_gbl|prop_inst|prop_sf|" @@ -126,27 +127,27 @@ void cmRST::Reset() if (!this->MarkupLines.empty()) { cmRST::UnindentLines(this->MarkupLines); } - switch (this->Directive) { - case DirectiveNone: + switch (this->DirectiveType) { + case Directive::None: break; - case DirectiveParsedLiteral: + case Directive::ParsedLiteral: this->ProcessDirectiveParsedLiteral(); break; - case DirectiveLiteralBlock: + case Directive::LiteralBlock: this->ProcessDirectiveLiteralBlock(); break; - case DirectiveCodeBlock: + case Directive::CodeBlock: this->ProcessDirectiveCodeBlock(); break; - case DirectiveReplace: + case Directive::Replace: this->ProcessDirectiveReplace(); break; - case DirectiveTocTree: + case Directive::TocTree: this->ProcessDirectiveTocTree(); break; } - this->Markup = MarkupNone; - this->Directive = DirectiveNone; + this->MarkupType = Markup::None; + this->DirectiveType = Directive::None; this->MarkupLines.clear(); } @@ -160,9 +161,9 @@ void cmRST::ProcessLine(std::string const& line) (line.size() >= 3 && line[0] == '.' && line[1] == '.' && isspace(line[2]))) { this->Reset(); - this->Markup = - (line.find_first_not_of(" \t", 2) == std::string::npos ? MarkupEmpty - : MarkupNormal); + this->MarkupType = + (line.find_first_not_of(" \t", 2) == std::string::npos ? Markup::Empty + : Markup::Normal); // XXX(clang-tidy): https://bugs.llvm.org/show_bug.cgi?id=44165 // NOLINTNEXTLINE(bugprone-branch-clone) if (this->CMakeDirective.find(line)) { @@ -171,33 +172,33 @@ void cmRST::ProcessLine(std::string const& line) } else if (this->CMakeModuleDirective.find(line)) { // Process cmake-module directive: scan .cmake file comments. std::string file = this->CMakeModuleDirective.match(1); - if (file.empty() || !this->ProcessInclude(file, IncludeModule)) { + if (file.empty() || !this->ProcessInclude(file, Include::Module)) { this->NormalLine(line); } } else if (this->ParsedLiteralDirective.find(line)) { // Record the literal lines to output after whole block. - this->Directive = DirectiveParsedLiteral; + this->DirectiveType = Directive::ParsedLiteral; this->MarkupLines.push_back(this->ParsedLiteralDirective.match(1)); } else if (this->CodeBlockDirective.find(line)) { // Record the literal lines to output after whole block. // Ignore the language spec and record the opening line as blank. - this->Directive = DirectiveCodeBlock; + this->DirectiveType = Directive::CodeBlock; this->MarkupLines.emplace_back(); } else if (this->ReplaceDirective.find(line)) { // Record the replace directive content. - this->Directive = DirectiveReplace; + this->DirectiveType = Directive::Replace; this->ReplaceName = this->ReplaceDirective.match(1); this->MarkupLines.push_back(this->ReplaceDirective.match(2)); } else if (this->IncludeDirective.find(line)) { // Process the include directive or output the directive and its // content normally if it fails. std::string file = this->IncludeDirective.match(1); - if (file.empty() || !this->ProcessInclude(file, IncludeNormal)) { + if (file.empty() || !this->ProcessInclude(file, Include::Normal)) { this->NormalLine(line); } } else if (this->TocTreeDirective.find(line)) { // Record the toctree entries to process after whole block. - this->Directive = DirectiveTocTree; + this->DirectiveType = Directive::TocTree; this->MarkupLines.push_back(this->TocTreeDirective.match(1)); } else if (this->ProductionListDirective.find(line)) { // Output productionlist directives and their content normally. @@ -211,14 +212,15 @@ void cmRST::ProcessLine(std::string const& line) this->NormalLine(line); } } - // An explicit markup start followed nothing but whitespace and a + // An explicit markup start followed by nothing but whitespace and a // blank line does not consume any indented text following. - else if (this->Markup == MarkupEmpty && line.empty()) { + else if (this->MarkupType == Markup::Empty && line.empty()) { this->NormalLine(line); } // Indented lines following an explicit markup start are explicit markup. - else if (this->Markup && (line.empty() || isspace(line[0]))) { - this->Markup = MarkupNormal; + else if (this->MarkupType != Markup::None && + (line.empty() || isspace(line[0]))) { + this->MarkupType = Markup::Normal; // Record markup lines if the start line was recorded. if (!this->MarkupLines.empty()) { this->MarkupLines.push_back(line); @@ -227,8 +229,8 @@ void cmRST::ProcessLine(std::string const& line) // A blank line following a paragraph ending in "::" starts a literal block. else if (lastLineEndedInColonColon && line.empty()) { // Record the literal lines to output after whole block. - this->Markup = MarkupNormal; - this->Directive = DirectiveLiteralBlock; + this->MarkupType = Markup::Normal; + this->DirectiveType = Directive::LiteralBlock; this->MarkupLines.emplace_back(); this->OutputLine("", false); } @@ -354,14 +356,14 @@ void cmRST::OutputMarkupLines(bool inlineMarkup) this->OutputLinePending = true; } -bool cmRST::ProcessInclude(std::string file, IncludeType type) +bool cmRST::ProcessInclude(std::string file, Include type) { bool found = false; if (this->IncludeDepth < 10) { cmRST r(this->OS, this->DocRoot); r.IncludeDepth = this->IncludeDepth + 1; r.OutputLinePending = this->OutputLinePending; - if (type != IncludeTocTree) { + if (type != Include::TocTree) { r.Replace = this->Replace; } if (file[0] == '/') { @@ -369,8 +371,8 @@ bool cmRST::ProcessInclude(std::string file, IncludeType type) } else { file = this->DocDir + "/" + file; } - found = r.ProcessFile(file, type == IncludeModule); - if (type != IncludeTocTree) { + found = r.ProcessFile(file, type == Include::Module); + if (type != Include::TocTree) { this->Replace = r.Replace; } this->OutputLinePending = r.OutputLinePending; @@ -408,9 +410,9 @@ void cmRST::ProcessDirectiveTocTree() if (!line.empty() && line[0] != ':') { if (this->TocTreeLink.find(line)) { std::string const& link = this->TocTreeLink.match(1); - this->ProcessInclude(link + ".rst", IncludeTocTree); + this->ProcessInclude(link + ".rst", Include::TocTree); } else { - this->ProcessInclude(line + ".rst", IncludeTocTree); + this->ProcessInclude(line + ".rst", Include::TocTree); } } } diff --git a/Source/cmRST.h b/Source/cmRST.h index ea4ef22..65a8a71 100644 --- a/Source/cmRST.h +++ b/Source/cmRST.h @@ -29,26 +29,26 @@ public: bool ProcessFile(std::string const& fname, bool isModule = false); private: - enum IncludeType + enum class Include { - IncludeNormal, - IncludeModule, - IncludeTocTree + Normal, + Module, + TocTree }; - enum MarkupType + enum class Markup { - MarkupNone, - MarkupNormal, - MarkupEmpty + None, + Normal, + Empty }; - enum DirectiveType + enum class Directive { - DirectiveNone, - DirectiveParsedLiteral, - DirectiveLiteralBlock, - DirectiveCodeBlock, - DirectiveReplace, - DirectiveTocTree + None, + ParsedLiteral, + LiteralBlock, + CodeBlock, + Replace, + TocTree }; void ProcessRST(std::istream& is); @@ -59,7 +59,7 @@ private: void OutputLine(std::string const& line, bool inlineMarkup); std::string ReplaceSubstitutions(std::string const& line); void OutputMarkupLines(bool inlineMarkup); - bool ProcessInclude(std::string file, IncludeType type); + bool ProcessInclude(std::string file, Include type); void ProcessDirectiveParsedLiteral(); void ProcessDirectiveLiteralBlock(); void ProcessDirectiveCodeBlock(); @@ -72,8 +72,8 @@ private: int IncludeDepth = 0; bool OutputLinePending = false; bool LastLineEndedInColonColon = false; - MarkupType Markup = MarkupNone; - DirectiveType Directive = DirectiveNone; + Markup MarkupType = Markup::None; + Directive DirectiveType = Directive::None; cmsys::RegularExpression CMakeDirective; cmsys::RegularExpression CMakeModuleDirective; cmsys::RegularExpression ParsedLiteralDirective; diff --git a/Source/cmSourceFile.h b/Source/cmSourceFile.h index c1c5201..9308af4 100644 --- a/Source/cmSourceFile.h +++ b/Source/cmSourceFile.h @@ -183,8 +183,8 @@ private: #define CM_HEADER_REGEX "\\.(h|hh|h\\+\\+|hm|hpp|hxx|in|txx|inl)$" #define CM_SOURCE_REGEX \ - "\\.(C|F|M|c|c\\+\\+|cc|cpp|mpp|cxx|ixx|cppm|cu|f|f90|for|fpp|ftn|m|mm|" \ - "rc|def|r|odl|idl|hpj|bat)$" + "\\.(C|F|M|c|c\\+\\+|cc|cpp|mpp|cxx|ixx|cppm|ccm|cxxm|c\\+\\+m|cu" \ + "|f|f90|for|fpp|ftn|m|mm|rc|def|r|odl|idl|hpj|bat)$" #define CM_PCH_REGEX "cmake_pch(_[^.]+)?\\.(h|hxx)$" diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index ec87271..5e55871 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -438,13 +438,16 @@ TargetProperty const StaticTargetProperties[] = { { "AUTOMOC_MACRO_NAMES"_s, IC::CanCompileSources }, { "AUTOMOC_MOC_OPTIONS"_s, IC::CanCompileSources }, { "AUTOMOC_PATH_PREFIX"_s, IC::CanCompileSources }, + { "AUTOMOC_EXECUTABLE"_s, IC::CanCompileSources }, // ---- uic { "AUTOUIC"_s, IC::CanCompileSources }, { "AUTOUIC_OPTIONS"_s, IC::CanCompileSources }, { "AUTOUIC_SEARCH_PATHS"_s, IC::CanCompileSources }, + { "AUTOUIC_EXECUTABLE"_s, IC::CanCompileSources }, // ---- rcc { "AUTORCC"_s, IC::CanCompileSources }, { "AUTORCC_OPTIONS"_s, IC::CanCompileSources }, + { "AUTORCC_EXECUTABLE"_s, IC::CanCompileSources }, // Linking properties { "ENABLE_EXPORTS"_s, IC::TargetWithSymbolExports }, @@ -552,6 +555,7 @@ TargetProperty const StaticTargetProperties[] = { { "JOB_POOL_PRECOMPILE_HEADER"_s, IC::CanCompileSources }, // -- Visual Studio { "VS_NO_COMPILE_BATCHING"_s, IC::CanCompileSources }, + { "VS_WINDOWS_TARGET_PLATFORM_MIN_VERSION"_s, IC::CanCompileSources}, // Output location properties { "ARCHIVE_OUTPUT_DIRECTORY"_s, IC::CanCompileSources }, @@ -1775,6 +1779,9 @@ MAKE_PROP(COMPILE_FEATURES); MAKE_PROP(COMPILE_OPTIONS); MAKE_PROP(PRECOMPILE_HEADERS); MAKE_PROP(PRECOMPILE_HEADERS_REUSE_FROM); +MAKE_PROP(CUDA_CUBIN_COMPILATION); +MAKE_PROP(CUDA_FATBIN_COMPILATION); +MAKE_PROP(CUDA_OPTIX_COMPILATION); MAKE_PROP(CUDA_PTX_COMPILATION); MAKE_PROP(EXPORT_NAME); MAKE_PROP(IMPORTED); @@ -1910,14 +1917,38 @@ void cmTarget::StoreProperty(const std::string& prop, ValueType value) value ? value : std::string{})) { // NOLINT(bugprone-branch-clone) /* error was reported by check method */ - } else if (prop == propCUDA_PTX_COMPILATION && - this->GetType() != cmStateEnums::OBJECT_LIBRARY) { - std::ostringstream e; - e << "CUDA_PTX_COMPILATION property can only be applied to OBJECT " - "targets (\"" - << this->impl->Name << "\")\n"; - this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e.str()); - return; + } else if (prop == propCUDA_CUBIN_COMPILATION || + prop == propCUDA_FATBIN_COMPILATION || + prop == propCUDA_OPTIX_COMPILATION || + prop == propCUDA_PTX_COMPILATION) { + auto const& compiler = + this->impl->Makefile->GetSafeDefinition("CMAKE_CUDA_COMPILER_ID"); + auto const& compilerVersion = + this->impl->Makefile->GetSafeDefinition("CMAKE_CUDA_COMPILER_VERSION"); + if (this->GetType() != cmStateEnums::OBJECT_LIBRARY) { + auto e = + cmStrCat(prop, " property can only be applied to OBJECT targets(", + this->impl->Name, ")\n"); + this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e); + return; + } + const bool flag_found = + (prop == propCUDA_PTX_COMPILATION && + this->impl->Makefile->GetDefinition("_CMAKE_CUDA_PTX_FLAG")) || + (prop == propCUDA_CUBIN_COMPILATION && + this->impl->Makefile->GetDefinition("_CMAKE_CUDA_CUBIN_FLAG")) || + (prop == propCUDA_FATBIN_COMPILATION && + this->impl->Makefile->GetDefinition("_CMAKE_CUDA_FATBIN_FLAG")) || + (prop == propCUDA_OPTIX_COMPILATION && + this->impl->Makefile->GetDefinition("_CMAKE_CUDA_OPTIX_FLAG")); + if (flag_found) { + this->impl->Properties.SetProperty(prop, value); + } else { + auto e = cmStrCat(prop, " property is not supported by ", compiler, + " compiler version ", compilerVersion, "."); + this->impl->Makefile->IssueMessage(MessageType::FATAL_ERROR, e); + return; + } } else if (prop == propPRECOMPILE_HEADERS_REUSE_FROM) { if (this->GetProperty("PRECOMPILE_HEADERS")) { std::ostringstream e; diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index d984c86..8926f9e 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -693,12 +693,12 @@ void cmVisualStudio10TargetGenerator::WriteClassicMsBuildProjectFile( switch (this->ProjectType) { case VsProjectType::vcxproj: { + Elem(e0, "Import").Attribute("Project", VS10_CXX_DEFAULT_PROPS); std::string const& props = this->GlobalGenerator->GetPlatformToolsetVersionProps(); if (!props.empty()) { Elem(e0, "Import").Attribute("Project", props); } - Elem(e0, "Import").Attribute("Project", VS10_CXX_DEFAULT_PROPS); } break; case VsProjectType::csproj: Elem(e0, "Import") @@ -1810,13 +1810,15 @@ void cmVisualStudio10TargetGenerator::WriteCustomRule( this->WriteCustomRuleCSharp(e0, c, name, script, additional_inputs.str(), outputs.str(), comment, ccg); } else { - this->WriteCustomRuleCpp( - *spe2, c, script, additional_inputs.str(), outputs.str(), comment, ccg, - symbolic, - (command.GetUsesTerminal() || - (command.HasMainDependency() && source->GetIsGenerated())) - ? BuildInParallel::No - : BuildInParallel::Yes); + BuildInParallel buildInParallel = BuildInParallel::No; + if (command.GetCMP0147Status() == cmPolicies::NEW && + !command.GetUsesTerminal() && + !(command.HasMainDependency() && source->GetIsGenerated())) { + buildInParallel = BuildInParallel::Yes; + } + this->WriteCustomRuleCpp(*spe2, c, script, additional_inputs.str(), + outputs.str(), comment, ccg, symbolic, + buildInParallel); } } } @@ -3595,13 +3597,13 @@ bool cmVisualStudio10TargetGenerator::ComputeCudaOptions( if (this->GeneratorTarget->GetPropertyAsBool("CUDA_SEPARABLE_COMPILATION")) { cudaOptions.AddFlag("GenerateRelocatableDeviceCode", "true"); } - bool notPtx = true; + bool notPtxLike = true; if (this->GeneratorTarget->GetPropertyAsBool("CUDA_PTX_COMPILATION")) { cudaOptions.AddFlag("NvccCompilation", "ptx"); // We drop the %(Extension) component as CMake expects all PTX files // to not have the source file extension at all cudaOptions.AddFlag("CompileOut", "$(IntDir)%(Filename).ptx"); - notPtx = false; + notPtxLike = false; if (cmSystemTools::VersionCompare(cmSystemTools::OP_GREATER_EQUAL, cudaVersion, "9.0") && @@ -3616,9 +3618,24 @@ bool cmVisualStudio10TargetGenerator::ComputeCudaOptions( "%(BaseCommandLineTemplate) [CompileOut] [FastMath] " "[Defines] \"%(FullPath)\""); } - } - - if (notPtx && + } else if (this->GeneratorTarget->GetPropertyAsBool( + "CUDA_CUBIN_COMPILATION")) { + cudaOptions.AddFlag("NvccCompilation", "cubin"); + cudaOptions.AddFlag("CompileOut", "$(IntDir)%(Filename).cubin"); + notPtxLike = false; + } else if (this->GeneratorTarget->GetPropertyAsBool( + "CUDA_FATBIN_COMPILATION")) { + cudaOptions.AddFlag("NvccCompilation", "fatbin"); + cudaOptions.AddFlag("CompileOut", "$(IntDir)%(Filename).fatbin"); + notPtxLike = false; + } else if (this->GeneratorTarget->GetPropertyAsBool( + "CUDA_OPTIX_COMPILATION")) { + cudaOptions.AddFlag("NvccCompilation", "optix-ir"); + cudaOptions.AddFlag("CompileOut", "$(IntDir)%(Filename).optixir"); + notPtxLike = false; + } + + if (notPtxLike && cmSystemTools::VersionCompareGreaterEq( "8.0", this->GlobalGenerator->GetPlatformToolsetCudaString())) { // Explicitly state that we want this file to be treated as a diff --git a/Source/cmake.cxx b/Source/cmake.cxx index db47e43..f943415 100644 --- a/Source/cmake.cxx +++ b/Source/cmake.cxx @@ -336,7 +336,7 @@ cmake::cmake(Role role, cmState::Mode mode, cmState::ProjectKind projectKind) // The "c" extension MUST precede the "C" extension. setupExts(this->CLikeSourceFileExtensions, { "c", "C", "c++", "cc", "cpp", "cxx", "cu", "mpp", "m", "M", - "mm", "ixx", "cppm" }); + "mm", "ixx", "cppm", "ccm", "cxxm", "c++m" }); setupExts(this->HeaderFileExtensions, { "h", "hh", "h++", "hm", "hpp", "hxx", "in", "txx" }); setupExts(this->CudaFileExtensions, { "cu" }); diff --git a/Source/kwsys/SystemTools.cxx b/Source/kwsys/SystemTools.cxx index 6cdd5a3..3bb7869 100644 --- a/Source/kwsys/SystemTools.cxx +++ b/Source/kwsys/SystemTools.cxx @@ -2528,6 +2528,12 @@ SystemTools::CopyStatus SystemTools::CloneFileContent( return status; #elif defined(__APPLE__) && \ defined(KWSYS_SYSTEMTOOLS_HAVE_MACOS_COPYFILE_CLONE) + // When running as root, copyfile() copies more metadata than we + // want, such as ownership. Pretend it is not available. + if (getuid() == 0) { + return CopyStatus{ Status::POSIX(ENOSYS), CopyStatus::NoPath }; + } + // NOTE: we cannot use `clonefile` as the {a,c,m}time for the file needs to // be updated by `copy_file_if_different` and `copy_file`. if (copyfile(source.c_str(), destination.c_str(), nullptr, diff --git a/Tests/CMakeLib/testRST.expect b/Tests/CMakeLib/testRST.expect index 5e3cdb1..424b7d4 100644 --- a/Tests/CMakeLib/testRST.expect +++ b/Tests/CMakeLib/testRST.expect @@ -26,10 +26,15 @@ Generator expression ``$<SOME_GENEX:...>`` with brackets and parameter. Generator expression ``some genex`` with space and target. Generator expression ``$<SOME_GENEX>`` with brackets, space, and target. Generator expression ``$<SOME_GENEX:...>`` with brackets, parameter, space, and target. -Inline literal ``~!@#$%^&*( )_+-=\\[]{}'":;,<>.?/``. +Inline cref ``Link Dest``. +Inline cref ``Link_Dest_<Placeholder>``. +Inline cref ``Link Text``. +Inline cref ``Link_Text_<Placeholder>``. +Inline link Link Dest. Inline link Link Text. Inline link Link Text <With \-escaped Brackets>. Inline literal ``__`` followed by inline link Link Text. +Inline literal ``~!@#$%^&*( )_+-=\\[]{}'":;,<>.?/``. First TOC entry. @@ -46,7 +51,8 @@ Bracket Comment Content Bracket Comment Content ] -.. cmake:command:: some_cmd +.. cmake:command:: + some_cmd Command some_cmd description. @@ -54,7 +60,8 @@ Bracket Comment Content Command other_cmd description. -.. cmake:envvar:: some_var +.. cmake:envvar:: + some_var Environment variable some_var description. @@ -62,7 +69,8 @@ Bracket Comment Content Environment variable other_var description. -.. cmake:genex:: SOME_GENEX +.. cmake:genex:: + SOME_GENEX Generator expression SOME_GENEX description. @@ -70,7 +78,17 @@ Bracket Comment Content Generator expression $<OTHER_GENEX> description. -.. cmake:variable:: some_var +.. cmake:signature:: + some_command(SOME_SIGNATURE) + + Command some_command SOME_SIGNATURE description. + +.. signature:: other_command(OTHER_SIGNATURE) + + Command other_command OTHER_SIGNATURE description. + +.. cmake:variable:: + some_var Variable some_var description. diff --git a/Tests/CMakeLib/testRST.rst b/Tests/CMakeLib/testRST.rst index 4139801..3a38407 100644 --- a/Tests/CMakeLib/testRST.rst +++ b/Tests/CMakeLib/testRST.rst @@ -33,10 +33,15 @@ Generator expression :genex:`$<SOME_GENEX:...>` with brackets and parameter. Generator expression :genex:`some genex <SOME_GENEX>` with space and target. Generator expression :genex:`$<SOME_GENEX> <SOME_GENEX>` with brackets, space, and target. Generator expression :genex:`$<SOME_GENEX:...> <SOME_GENEX>` with brackets, parameter, space, and target. -Inline literal ``~!@#$%^&*( )_+-=\\[]{}'":;,<>.?/``. +Inline cref :cref:`Link Dest`. +Inline cref :cref:`Link_Dest_<Placeholder>`. +Inline cref :cref:`Link Text <ExternalDest>`. +Inline cref :cref:`Link_Text_<Placeholder> <ExternalDest>`. +Inline link `Link Dest`_. Inline link `Link Text <ExternalDest>`_. Inline link `Link Text \<With \\-escaped Brackets\> <ExternalDest>`_. Inline literal ``__`` followed by inline link `Link Text <InternalDest_>`_. +Inline literal ``~!@#$%^&*( )_+-=\\[]{}'":;,<>.?/``. .. |not replaced| replace:: not replaced through toctree .. |not replaced in literal| replace:: replaced in parsed literal @@ -49,7 +54,8 @@ Inline literal ``__`` followed by inline link `Link Text <InternalDest_>`_. .. cmake-module:: testRSTmod.cmake -.. cmake:command:: some_cmd +.. cmake:command:: + some_cmd Command some_cmd description. @@ -57,7 +63,8 @@ Inline literal ``__`` followed by inline link `Link Text <InternalDest_>`_. Command other_cmd description. -.. cmake:envvar:: some_var +.. cmake:envvar:: + some_var Environment variable some_var description. @@ -65,7 +72,8 @@ Inline literal ``__`` followed by inline link `Link Text <InternalDest_>`_. Environment variable other_var description. -.. cmake:genex:: SOME_GENEX +.. cmake:genex:: + SOME_GENEX Generator expression SOME_GENEX description. @@ -73,7 +81,17 @@ Inline literal ``__`` followed by inline link `Link Text <InternalDest_>`_. Generator expression $<OTHER_GENEX> description. -.. cmake:variable:: some_var +.. cmake:signature:: + some_command(SOME_SIGNATURE) + + Command some_command SOME_SIGNATURE description. + +.. signature:: other_command(OTHER_SIGNATURE) + + Command other_command OTHER_SIGNATURE description. + +.. cmake:variable:: + some_var Variable some_var description. diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt index d913e93..e92d1c1 100644 --- a/Tests/CMakeLists.txt +++ b/Tests/CMakeLists.txt @@ -1450,6 +1450,7 @@ if(BUILD_TESTING) GnuTLS GSL GTK2 + HDF5 Iconv ICU ImageMagick @@ -1484,6 +1485,7 @@ if(BUILD_TESTING) SQLite3 TIFF Vulkan + wxWidgets X11 XalanC XercesC diff --git a/Tests/CudaOnly/CMakeLists.txt b/Tests/CudaOnly/CMakeLists.txt index db08076..aa25c4c 100644 --- a/Tests/CudaOnly/CMakeLists.txt +++ b/Tests/CudaOnly/CMakeLists.txt @@ -27,6 +27,9 @@ if(CMake_TEST_CUDA AND NOT CMake_TEST_CUDA STREQUAL "Clang") # Only NVCC defines __CUDACC_DEBUG__ when compiling in debug mode. add_cuda_test_macro(CudaOnly.GPUDebugFlag CudaOnlyGPUDebugFlag) + add_cuda_test_macro(CudaOnly.CUBIN CudaOnlyCUBIN) + add_cuda_test_macro(CudaOnly.Fatbin CudaOnlyFatbin) + add_cuda_test_macro(CudaOnly.OptixIR CudaOnlyOptixIR) endif() add_cuda_test_macro(CudaOnly.DeviceLTO CudaOnlyDeviceLTO) diff --git a/Tests/CudaOnly/CUBIN/CMakeLists.txt b/Tests/CudaOnly/CUBIN/CMakeLists.txt new file mode 100644 index 0000000..81787e4 --- /dev/null +++ b/Tests/CudaOnly/CUBIN/CMakeLists.txt @@ -0,0 +1,29 @@ +cmake_minimum_required(VERSION 3.18) +unset(ENV{CMAKE_CUDA_ARCHITECTURES_NATIVE_CLAMP}) # CUBIN needs true native arch +project(CudaCUBIN LANGUAGES CUDA) + +set(CMAKE_CUDA_ARCHITECTURES all-major) + +# CUBIN needs the true native arch to be supported by the CUDA toolkit. +set(unavailable_native_archs "${CMAKE_CUDA_ARCHITECTURES_NATIVE}") +list(REMOVE_ITEM unavailable_native_archs ${CMAKE_CUDA_ARCHITECTURES_ALL}) +if(unavailable_native_archs) + add_executable(CudaOnlyCUBIN main_no_native_archs.cu) + return() +endif() + +add_library(CudaCUBIN OBJECT kernelA.cu kernelB.cu kernelC.cu) +set_property(TARGET CudaCUBIN PROPERTY CUDA_CUBIN_COMPILATION ON) +set_property(TARGET CudaCUBIN PROPERTY CUDA_ARCHITECTURES native) + +add_executable(CudaOnlyCUBIN main.cu) +target_compile_features(CudaOnlyCUBIN PRIVATE cuda_std_11) +target_compile_definitions(CudaOnlyCUBIN PRIVATE "CUBIN_FILE_PATHS=\"$<JOIN:$<TARGET_OBJECTS:CudaCUBIN>,~_~>\"") + +find_package(CUDAToolkit REQUIRED) +target_link_libraries(CudaOnlyCUBIN PRIVATE CUDA::cuda_driver) + +if(APPLE) + # Help the static cuda runtime find the driver (libcuda.dyllib) at runtime. + set_property(TARGET CudaOnlyCUBIN PROPERTY BUILD_RPATH ${CMAKE_CUDA_IMPLICIT_LINK_DIRECTORIES}) +endif() diff --git a/Tests/CudaOnly/CUBIN/kernelA.cu b/Tests/CudaOnly/CUBIN/kernelA.cu new file mode 100644 index 0000000..fbe0d26 --- /dev/null +++ b/Tests/CudaOnly/CUBIN/kernelA.cu @@ -0,0 +1,7 @@ + +__global__ void kernelA(float* r, float* x, float* y, float* z, int size) +{ + for (int i = threadIdx.x; i < size; i += blockDim.x) { + r[i] = x[i] * y[i] + z[i]; + } +} diff --git a/Tests/CudaOnly/CUBIN/kernelB.cu b/Tests/CudaOnly/CUBIN/kernelB.cu new file mode 100644 index 0000000..7478253 --- /dev/null +++ b/Tests/CudaOnly/CUBIN/kernelB.cu @@ -0,0 +1,7 @@ + +__global__ void kernelB(float* r, float* x, float* y, float* z, int size) +{ + for (int i = threadIdx.x; i < size; i += blockDim.x) { + r[i] = x[i] * y[i] + z[i]; + } +} diff --git a/Tests/CudaOnly/CUBIN/kernelC.cu b/Tests/CudaOnly/CUBIN/kernelC.cu new file mode 100644 index 0000000..5f8a0ce --- /dev/null +++ b/Tests/CudaOnly/CUBIN/kernelC.cu @@ -0,0 +1,7 @@ + +__global__ void kernelC(float* r, float* x, float* y, float* z, int size) +{ + for (int i = threadIdx.x; i < size; i += blockDim.x) { + r[i] = x[i] * y[i] + z[i]; + } +} diff --git a/Tests/CudaOnly/CUBIN/main.cu b/Tests/CudaOnly/CUBIN/main.cu new file mode 100644 index 0000000..581970a --- /dev/null +++ b/Tests/CudaOnly/CUBIN/main.cu @@ -0,0 +1,58 @@ +#include <iostream> +#include <string> +#include <vector> + +#include <cuda.h> + +#define GENERATED_HEADER(x) GENERATED_HEADER1(x) +#define GENERATED_HEADER1(x) <x> + +static std::string input_paths = { CUBIN_FILE_PATHS }; + +int main() +{ + const std::string delimiter = "~_~"; + input_paths += delimiter; + + size_t end = 0; + size_t previous_end = 0; + std::vector<std::string> actual_paths; + while ((end = input_paths.find(delimiter, previous_end)) != + std::string::npos) { + actual_paths.emplace_back( + input_paths.substr(previous_end, end - previous_end)); + previous_end = end + 3; + } + + cuInit(0); + int count = 0; + cuDeviceGetCount(&count); + if (count == 0) { + std::cerr << "No CUDA devices found\n"; + return 1; + } + + CUdevice device; + cuDeviceGet(&device, 0); + + CUcontext context; + cuCtxCreate(&context, 0, device); + + CUmodule module; + for (auto p : actual_paths) { + if (p.find(".cubin") == std::string::npos) { + std::cout << p << " Doesn't have the .cubin suffix" << p << std::endl; + return 1; + } + std::cout << "trying to load cubin: " << p << std::endl; + CUresult result = cuModuleLoad(&module, p.c_str()); + std::cout << "module pointer: " << module << '\n'; + if (result != CUDA_SUCCESS || module == nullptr) { + std::cerr << "Failed to load the embedded cubin with error: " + << static_cast<unsigned int>(result) << '\n'; + return 1; + } + } + + return 0; +} diff --git a/Tests/CudaOnly/CUBIN/main_no_native_archs.cu b/Tests/CudaOnly/CUBIN/main_no_native_archs.cu new file mode 100644 index 0000000..f8b643a --- /dev/null +++ b/Tests/CudaOnly/CUBIN/main_no_native_archs.cu @@ -0,0 +1,4 @@ +int main() +{ + return 0; +} diff --git a/Tests/CudaOnly/Fatbin/CMakeLists.txt b/Tests/CudaOnly/Fatbin/CMakeLists.txt new file mode 100644 index 0000000..db0dc22 --- /dev/null +++ b/Tests/CudaOnly/Fatbin/CMakeLists.txt @@ -0,0 +1,25 @@ +cmake_minimum_required(VERSION 3.18) +project(CudaFATBIN LANGUAGES CUDA) + + +set(CMAKE_CUDA_ARCHITECTURES all-major) + +add_library(CudaFATBIN OBJECT +${CMAKE_CURRENT_SOURCE_DIR}/../CUBIN/kernelA.cu +${CMAKE_CURRENT_SOURCE_DIR}/../CUBIN/kernelB.cu +${CMAKE_CURRENT_SOURCE_DIR}/../CUBIN/kernelC.cu) + +set_property(TARGET CudaFATBIN PROPERTY CUDA_FATBIN_COMPILATION ON) + +# Will use `cuModuleLoadFatBinary` to load the fatbinaries +add_executable(CudaOnlyFatbin main.cu) +target_compile_features(CudaOnlyFatbin PRIVATE cuda_std_11) +target_compile_definitions(CudaOnlyFatbin PRIVATE "FATBIN_FILE_PATHS=\"$<JOIN:$<TARGET_OBJECTS:CudaFATBIN>,~_~>\"") + +find_package(CUDAToolkit REQUIRED) +target_link_libraries(CudaOnlyFatbin PRIVATE CUDA::cuda_driver) + +if(APPLE) + # Help the static cuda runtime find the driver (libcuda.dyllib) at runtime. + set_property(TARGET CudaOnlyFatbin PROPERTY BUILD_RPATH ${CMAKE_CUDA_IMPLICIT_LINK_DIRECTORIES}) +endif() diff --git a/Tests/CudaOnly/Fatbin/main.cu b/Tests/CudaOnly/Fatbin/main.cu new file mode 100644 index 0000000..89af0e3 --- /dev/null +++ b/Tests/CudaOnly/Fatbin/main.cu @@ -0,0 +1,58 @@ +#include <iostream> +#include <string> +#include <vector> + +#include <cuda.h> + +#define GENERATED_HEADER(x) GENERATED_HEADER1(x) +#define GENERATED_HEADER1(x) <x> + +static std::string input_paths = { FATBIN_FILE_PATHS }; + +int main() +{ + const std::string delimiter = "~_~"; + input_paths += delimiter; + + size_t end = 0; + size_t previous_end = 0; + std::vector<std::string> actual_paths; + while ((end = input_paths.find(delimiter, previous_end)) != + std::string::npos) { + actual_paths.emplace_back( + input_paths.substr(previous_end, end - previous_end)); + previous_end = end + 3; + } + + cuInit(0); + int count = 0; + cuDeviceGetCount(&count); + if (count == 0) { + std::cerr << "No CUDA devices found\n"; + return 1; + } + + CUdevice device; + cuDeviceGet(&device, 0); + + CUcontext context; + cuCtxCreate(&context, 0, device); + + CUmodule module; + for (auto p : actual_paths) { + if (p.find(".fatbin") == std::string::npos) { + std::cout << p << " Doesn't have the .fatbin suffix" << p << std::endl; + return 1; + } + std::cout << "trying to load fatbin: " << p << std::endl; + CUresult result = cuModuleLoad(&module, p.c_str()); + std::cout << "module pointer: " << module << '\n'; + if (result != CUDA_SUCCESS || module == nullptr) { + std::cerr << "Failed to load the embedded fatbin with error: " + << static_cast<unsigned int>(result) << '\n'; + return 1; + } + } + + return 0; +} diff --git a/Tests/CudaOnly/OptixIR/CMakeLists.txt b/Tests/CudaOnly/OptixIR/CMakeLists.txt new file mode 100644 index 0000000..afeabda --- /dev/null +++ b/Tests/CudaOnly/OptixIR/CMakeLists.txt @@ -0,0 +1,33 @@ +cmake_minimum_required(VERSION 3.18) +project(CudaOptix LANGUAGES CUDA) + + +set(CMAKE_CUDA_ARCHITECTURES all-major) + +add_library(CudaOptix OBJECT + ${CMAKE_CURRENT_SOURCE_DIR}/../CUBIN/kernelA.cu + ${CMAKE_CURRENT_SOURCE_DIR}/../CUBIN/kernelB.cu + ${CMAKE_CURRENT_SOURCE_DIR}/../CUBIN/kernelC.cu) + +if(CMAKE_CUDA_COMPILER_VERSION VERSION_GREATER_EQUAL "11.7.0") + set_property(TARGET CudaOptix PROPERTY CUDA_OPTIX_COMPILATION ON) +endif() + +set_property(TARGET CudaOptix PROPERTY CUDA_ARCHITECTURES native) + +add_executable(CudaOnlyOptixIR main.cu) +target_compile_features(CudaOnlyOptixIR PRIVATE cuda_std_11) + +if(CMAKE_CUDA_COMPILER_VERSION VERSION_GREATER_EQUAL "11.7.0") + target_compile_definitions(CudaOnlyOptixIR PRIVATE "OPTIX_FILE_PATHS=\"$<JOIN:$<TARGET_OBJECTS:CudaOptix>,~_~>\"") +else() + target_compile_definitions(CudaOnlyOptixIR PRIVATE "OPTIX_FILE_PATHS=\"NO_OPTIX_SUPPORT\"") +endif() + +find_package(CUDAToolkit REQUIRED) +target_link_libraries(CudaOnlyOptixIR PRIVATE CUDA::cuda_driver) + +if(APPLE) + # Help the static cuda runtime find the driver (libcuda.dyllib) at runtime. + set_property(TARGET CudaOnlyOptixIR PROPERTY BUILD_RPATH ${CMAKE_CUDA_IMPLICIT_LINK_DIRECTORIES}) +endif() diff --git a/Tests/CudaOnly/OptixIR/main.cu b/Tests/CudaOnly/OptixIR/main.cu new file mode 100644 index 0000000..c79829b --- /dev/null +++ b/Tests/CudaOnly/OptixIR/main.cu @@ -0,0 +1,53 @@ +#include <fstream> +#include <iostream> +#include <string> +#include <vector> + +#include <cuda.h> + +#define GENERATED_HEADER(x) GENERATED_HEADER1(x) +#define GENERATED_HEADER1(x) <x> + +static std::string input_paths = { OPTIX_FILE_PATHS }; + +int main() +{ + if (input_paths == "NO_OPTIX_SUPPORT") { + return 0; + } + + const std::string delimiter = "~_~"; + input_paths += delimiter; + + size_t end = 0; + size_t previous_end = 0; + std::vector<std::string> actual_paths; + while ((end = input_paths.find(delimiter, previous_end)) != + std::string::npos) { + actual_paths.emplace_back( + input_paths.substr(previous_end, end - previous_end)); + previous_end = end + 3; + } + + if (actual_paths.empty()) { + std::cerr << "Failed to parse OPTIX_FILE_PATHS" << std::endl; + return 1; + } + + const std::uint32_t optix_magic_value = 0x7f4e43ed; + for (auto p : actual_paths) { + if (p.find(".optixir") == std::string::npos) { + std::cout << p << " Doesn't have the .optixir suffix" << p << std::endl; + return 1; + } + std::ifstream input(p, std::ios::binary); + std::uint32_t value; + input.read(reinterpret_cast<char*>(&value), sizeof(value)); + if (value != optix_magic_value) { + std::cerr << p << " Doesn't look like an optix-ir file" << std::endl; + return 1; + } + } + + return 0; +} diff --git a/Tests/CudaOnly/RuntimeControls/verify_runtime.cmake b/Tests/CudaOnly/RuntimeControls/verify_runtime.cmake index b313dac..27fbe45 100644 --- a/Tests/CudaOnly/RuntimeControls/verify_runtime.cmake +++ b/Tests/CudaOnly/RuntimeControls/verify_runtime.cmake @@ -7,7 +7,7 @@ file(GET_RUNTIME_DEPENDENCIES EXECUTABLES ${EXEC_PATH} ) -list(FILTER resolved_libs INCLUDE REGEX ".*cudart.*") +list(FILTER resolved_libs INCLUDE REGEX ".*[Cc][Uu][Dd][Aa][Rr][Tt].*") list(LENGTH resolved_libs has_cudart) if(has_cudart EQUAL 0) diff --git a/Tests/EnforceConfig.cmake.in b/Tests/EnforceConfig.cmake.in index 61be40b..a652efc 100644 --- a/Tests/EnforceConfig.cmake.in +++ b/Tests/EnforceConfig.cmake.in @@ -35,5 +35,8 @@ unset(ENV{CMAKE_GENERATOR_PLATFORM}) unset(ENV{CMAKE_GENERATOR_TOOLSET}) unset(ENV{CMAKE_EXPORT_COMPILE_COMMANDS}) +# Verify that our module implementations do not recurse too much. +set(ENV{CMAKE_MAXIMUM_RECURSION_DEPTH} 100) + @TEST_HOME_ENV_CODE@ @TEST_WARN_VS_CODE@ diff --git a/Tests/FindBLAS/Test/CMakeLists.txt b/Tests/FindBLAS/Test/CMakeLists.txt index 14bf19f..9909d2e 100644 --- a/Tests/FindBLAS/Test/CMakeLists.txt +++ b/Tests/FindBLAS/Test/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.4) +cmake_minimum_required(VERSION 3.5) project(TestFindBLAS C) include(CTest) diff --git a/Tests/FindBZip2/Test/CMakeLists.txt b/Tests/FindBZip2/Test/CMakeLists.txt index e9cb618..136b3fd 100644 --- a/Tests/FindBZip2/Test/CMakeLists.txt +++ b/Tests/FindBZip2/Test/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.4) +cmake_minimum_required(VERSION 3.5) project(TestFindBZip2 C) include(CTest) diff --git a/Tests/FindBoost/Test/CMakeLists.txt b/Tests/FindBoost/Test/CMakeLists.txt index f60ccfa..39fa532 100644 --- a/Tests/FindBoost/Test/CMakeLists.txt +++ b/Tests/FindBoost/Test/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.1) +cmake_minimum_required(VERSION 3.5) project(TestFindBoost CXX) include(CTest) diff --git a/Tests/FindBoost/TestFail/CMakeLists.txt b/Tests/FindBoost/TestFail/CMakeLists.txt index 7c14a59..3db1a4f 100644 --- a/Tests/FindBoost/TestFail/CMakeLists.txt +++ b/Tests/FindBoost/TestFail/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.1) +cmake_minimum_required(VERSION 3.5) project(TestFindBoost CXX) include(CTest) diff --git a/Tests/FindBoost/TestHeaders/CMakeLists.txt b/Tests/FindBoost/TestHeaders/CMakeLists.txt index d7be327..7dd12e9 100644 --- a/Tests/FindBoost/TestHeaders/CMakeLists.txt +++ b/Tests/FindBoost/TestHeaders/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.1) +cmake_minimum_required(VERSION 3.5) project(TestFindBoostHeaders CXX) include(CTest) diff --git a/Tests/FindDevIL/Test/CMakeLists.txt b/Tests/FindDevIL/Test/CMakeLists.txt index c2c1322..db80ccb 100644 --- a/Tests/FindDevIL/Test/CMakeLists.txt +++ b/Tests/FindDevIL/Test/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.1) +cmake_minimum_required(VERSION 3.5) project(TestFindDevIL C) include(CTest) diff --git a/Tests/FindGIF/Test/CMakeLists.txt b/Tests/FindGIF/Test/CMakeLists.txt index 961e636..eb0291e 100644 --- a/Tests/FindGIF/Test/CMakeLists.txt +++ b/Tests/FindGIF/Test/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.4) +cmake_minimum_required(VERSION 3.5) project(TestFindGIF C) include(CTest) diff --git a/Tests/FindGLEW/Test/CMakeLists.txt b/Tests/FindGLEW/Test/CMakeLists.txt index 954ee10..de8d97d 100644 --- a/Tests/FindGLEW/Test/CMakeLists.txt +++ b/Tests/FindGLEW/Test/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.1) +cmake_minimum_required(VERSION 3.5) project(TestFindGLEW LANGUAGES CXX) include(CTest) diff --git a/Tests/FindGSL/rng/CMakeLists.txt b/Tests/FindGSL/rng/CMakeLists.txt index b15d6ac..497b6c3 100644 --- a/Tests/FindGSL/rng/CMakeLists.txt +++ b/Tests/FindGSL/rng/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.0) +cmake_minimum_required(VERSION 3.5) project(FindGSL_rng CXX) include(CTest) diff --git a/Tests/FindGTest/Test/CMakeLists.txt b/Tests/FindGTest/Test/CMakeLists.txt index 9c1eb5e..582cbaa 100644 --- a/Tests/FindGTest/Test/CMakeLists.txt +++ b/Tests/FindGTest/Test/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.1) +cmake_minimum_required(VERSION 3.5) project(TestFindGTest CXX) include(CTest) diff --git a/Tests/FindGnuTLS/Test/CMakeLists.txt b/Tests/FindGnuTLS/Test/CMakeLists.txt index c5a9819..e17987d 100644 --- a/Tests/FindGnuTLS/Test/CMakeLists.txt +++ b/Tests/FindGnuTLS/Test/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.4) +cmake_minimum_required(VERSION 3.5) project(TestFindGnuTLS C) include(CTest) diff --git a/Tests/FindHDF5/CMakeLists.txt b/Tests/FindHDF5/CMakeLists.txt new file mode 100644 index 0000000..373759e --- /dev/null +++ b/Tests/FindHDF5/CMakeLists.txt @@ -0,0 +1,84 @@ +# These tests may be configured by cache entries: +# +# CMake_TEST_FindHDF5:BOOL=ON +# Enable this directory. +# +# CMake_TEST_FindHDF5_<variant>_<lang>_COMPILER:FILEPATH=... +# Enable testing for a variant/language combination with the given wrapper. +# Variants: Serial, OpenMPI, MPICH +# Languages: C, CXX, Fortran +# +# CMake_TEST_FindHDF5_<variant>_<lang>_COMPILER_EXPLICIT:BOOL=ON +# Pass the above wrapper path to the test as HDF5_<lang>_COMPILER_EXECUTABLE. + +set(test_langs C CXX) +if(CMAKE_Fortran_COMPILER) + list(APPEND test_langs Fortran) +endif() + +# Test detection without any special hints. +add_test(NAME FindHDF5.Default COMMAND + ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION> + --build-and-test + "${CMake_SOURCE_DIR}/Tests/FindHDF5/Test" + "${CMake_BINARY_DIR}/Tests/FindHDF5/Test-Default" + ${build_generator_args} + --build-project TestFindHDF5 + --build-options ${build_options} -DTEST_SERIAL=1 "-DTEST_LANGS=${test_langs}" + ) + +foreach(variant Serial OpenMPI MPICH) + set(wrapper "") + set(wrapper_langs "") + set(wrapper_as_compiler "") + foreach(lang IN LISTS test_langs) + if(CMake_TEST_FindHDF5_${variant}_${lang}_COMPILER) + list(APPEND wrapper_langs ${lang}) + list(APPEND wrapper_as_compiler -DCMAKE_${lang}_COMPILER=${CMake_TEST_FindHDF5_${variant}_${lang}_COMPILER}) + if(CMake_TEST_FindHDF5_${variant}_${lang}_COMPILER_EXPLICIT) + list(APPEND wrapper -DHDF5_${lang}_COMPILER_EXECUTABLE=${CMake_TEST_FindHDF5_${variant}_${lang}_COMPILER}) + endif() + endif() + endforeach() + + if(NOT wrapper_langs) + continue() + endif() + + if(variant STREQUAL "Serial") + set(test_kind -DTEST_SERIAL=1) + else() + set(test_kind -DTEST_PARALLEL=1) + endif() + + # Test detection using the HDF5 compiler wrappers as a reference. + add_test(NAME FindHDF5.${variant} COMMAND + ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION> + --build-and-test + "${CMake_SOURCE_DIR}/Tests/FindHDF5/Test" + "${CMake_BINARY_DIR}/Tests/FindHDF5/Test-${variant}" + ${build_generator_args} + --build-project TestFindHDF5 + --build-options ${build_options} ${test_kind} "-DTEST_LANGS=${wrapper_langs}" ${wrapper} + ) + if(CMake_TEST_FindHDF5_${variant}_ENVMOD) + set_property(TEST FindHDF5.${variant} PROPERTY ENVIRONMENT_MODIFICATION ${CMake_TEST_FindHDF5_${variant}_ENVMOD}) + endif() + + # Test detection using the HDF5 compiler wrappers as the compiler. + # Skip this if there are spaces in the path. The HDF5 wrappers do not like them. + if(NOT CMAKE_CURRENT_BINARY_DIR MATCHES " ") + add_test(NAME FindHDF5.${variant}-Wrapper COMMAND + ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION> + --build-and-test + "${CMake_SOURCE_DIR}/Tests/FindHDF5/Test" + "${CMake_BINARY_DIR}/Tests/FindHDF5/Test-${variant}-Wrapper" + ${build_generator_args} + --build-project TestFindHDF5 + --build-options ${build_options} ${test_kind} "-DTEST_LANGS=${wrapper_langs}" -D TEST_WRAPPER_AS_COMPILER=1 ${wrapper_as_compiler} + ) + if(CMake_TEST_FindHDF5_${variant}_ENVMOD) + set_property(TEST FindHDF5.${variant}-Wrapper PROPERTY ENVIRONMENT_MODIFICATION ${CMake_TEST_FindHDF5_${variant}_ENVMOD}) + endif() + endif() +endforeach() diff --git a/Tests/FindHDF5/Test/CMakeLists.txt b/Tests/FindHDF5/Test/CMakeLists.txt new file mode 100644 index 0000000..53ad633 --- /dev/null +++ b/Tests/FindHDF5/Test/CMakeLists.txt @@ -0,0 +1,58 @@ +cmake_minimum_required(VERSION 3.26) +project(TestFindHDF5 LANGUAGES ${TEST_LANGS}) +message(STATUS "CTEST_FULL_OUTPUT (Avoid ctest truncation of output)") + +if(TEST_PARALLEL) + set(HDF5_PREFER_PARALLEL 1) +endif() + +find_package(HDF5 REQUIRED COMPONENTS ${TEST_LANGS} HL) + +set(variables HDF5_FOUND HDF5_VERSION) +if(NOT TEST_WRAPPER_AS_COMPILER) + list(APPEND variables HDF5_INCLUDE_DIRS HDF5_LIBRARIES HDF5_HL_LIBRARIES) + foreach(lang ${TEST_LANGS}) + list(APPEND variables + HDF5_${lang}_COMPILER_EXECUTABLE + HDF5_${lang}_INCLUDE_DIRS + HDF5_${lang}_LIBRARIES + HDF5_${lang}_HL_LIBRARIES + ) + endforeach() + endif() +foreach(var IN LISTS variables) + message(STATUS "${var}='${${var}}'") +endforeach() +foreach(var IN LISTS variables) + if(NOT DEFINED ${var}) + message(SEND_ERROR "Variable '${var}' is not defined!") + endif() +endforeach() + +set(targets HDF5::HDF5) +if(CMAKE_C_COMPILER_LOADED) + list(APPEND targets hdf5::hdf5 hdf5::hdf5_hl) +endif() +if(CMAKE_CXX_COMPILER_LOADED) + list(APPEND targets hdf5::hdf5_cpp hdf5::hdf5_hl_cpp) +endif() +if(CMAKE_Fortran_COMPILER_LOADED) + list(APPEND targets hdf5::hdf5_fortran hdf5::hdf5_hl_fortran) +endif() +foreach(target IN LISTS targets) + if(NOT TARGET ${target}) + message(SEND_ERROR "Target '${target}' not defined!") + endif() +endforeach() + +message(STATUS "HDF5_IS_PARALLEL='${HDF5_IS_PARALLEL}'") +if(TEST_SERIAL) + if(HDF5_IS_PARALLEL) + message(SEND_ERROR "HDF5_IS_PARALLEL is true in serial test.") + endif() +endif() +if(TEST_PARALLEL) + if(NOT HDF5_IS_PARALLEL) + message(SEND_ERROR "HDF5_IS_PARALLEL is false in parallel test.") + endif() +endif() diff --git a/Tests/FindICU/Test/CMakeLists.txt b/Tests/FindICU/Test/CMakeLists.txt index 1247ac7..066d173 100644 --- a/Tests/FindICU/Test/CMakeLists.txt +++ b/Tests/FindICU/Test/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.1) +cmake_minimum_required(VERSION 3.5) project(TestFindICU LANGUAGES CXX) include(CTest) diff --git a/Tests/FindImageMagick/Test/CMakeLists.txt b/Tests/FindImageMagick/Test/CMakeLists.txt index 6182260..4e4f14d 100644 --- a/Tests/FindImageMagick/Test/CMakeLists.txt +++ b/Tests/FindImageMagick/Test/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.4) +cmake_minimum_required(VERSION 3.5) project(FindImageMagick C CXX) include(CTest) diff --git a/Tests/FindJPEG/Test/CMakeLists.txt b/Tests/FindJPEG/Test/CMakeLists.txt index 912c7a1..390b3a7 100644 --- a/Tests/FindJPEG/Test/CMakeLists.txt +++ b/Tests/FindJPEG/Test/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.1) +cmake_minimum_required(VERSION 3.5) project(TestFindJPEG C) include(CTest) diff --git a/Tests/FindJsonCpp/Test/CMakeLists.txt b/Tests/FindJsonCpp/Test/CMakeLists.txt index d1dc647..5f100ea 100644 --- a/Tests/FindJsonCpp/Test/CMakeLists.txt +++ b/Tests/FindJsonCpp/Test/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.1) +cmake_minimum_required(VERSION 3.5) project(TestFindJsonCpp CXX) include(CTest) diff --git a/Tests/FindLAPACK/Test/CMakeLists.txt b/Tests/FindLAPACK/Test/CMakeLists.txt index f5d5a73..ce9af98 100644 --- a/Tests/FindLAPACK/Test/CMakeLists.txt +++ b/Tests/FindLAPACK/Test/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.4) +cmake_minimum_required(VERSION 3.5) project(TestFindLAPACK C) include(CTest) diff --git a/Tests/FindLibLZMA/Test/CMakeLists.txt b/Tests/FindLibLZMA/Test/CMakeLists.txt index c59dcdb..438938e 100644 --- a/Tests/FindLibLZMA/Test/CMakeLists.txt +++ b/Tests/FindLibLZMA/Test/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.4) +cmake_minimum_required(VERSION 3.5) project(TestFindLZMA C) include(CTest) diff --git a/Tests/FindLibXml2/Test/CMakeLists.txt b/Tests/FindLibXml2/Test/CMakeLists.txt index 041cc13..9b866ab 100644 --- a/Tests/FindLibXml2/Test/CMakeLists.txt +++ b/Tests/FindLibXml2/Test/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.4) +cmake_minimum_required(VERSION 3.5) project(TestFindLibXml2 C) include(CTest) diff --git a/Tests/FindLibXslt/Test/CMakeLists.txt b/Tests/FindLibXslt/Test/CMakeLists.txt index e932661..32a157f 100644 --- a/Tests/FindLibXslt/Test/CMakeLists.txt +++ b/Tests/FindLibXslt/Test/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.4) +cmake_minimum_required(VERSION 3.5) project(TestFindLibXslt C) include(CTest) diff --git a/Tests/FindMPI/CMakeLists.txt b/Tests/FindMPI/CMakeLists.txt index 121d978..1bc12c8 100644 --- a/Tests/FindMPI/CMakeLists.txt +++ b/Tests/FindMPI/CMakeLists.txt @@ -19,3 +19,6 @@ add_test(NAME FindMPI.Test COMMAND -DMPI_TEST_Fortran=${CMake_TEST_FindMPI_FLAG_Fortran} --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION> ) +if(CMake_TEST_FindMPI_ENVMOD) + set_property(TEST FindMPI.Test PROPERTY ENVIRONMENT_MODIFICATION ${CMake_TEST_FindMPI_ENVMOD}) +endif() diff --git a/Tests/FindODBC/Test/CMakeLists.txt b/Tests/FindODBC/Test/CMakeLists.txt index a20c0f7..1e3a239 100644 --- a/Tests/FindODBC/Test/CMakeLists.txt +++ b/Tests/FindODBC/Test/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.1) +cmake_minimum_required(VERSION 3.5) project(TestFindODBC C) include(CTest) diff --git a/Tests/FindOpenAL/Test/CMakeLists.txt b/Tests/FindOpenAL/Test/CMakeLists.txt index fa3e263..6479df6 100644 --- a/Tests/FindOpenAL/Test/CMakeLists.txt +++ b/Tests/FindOpenAL/Test/CMakeLists.txt @@ -12,3 +12,9 @@ add_executable(test_var main.cxx) target_include_directories(test_var PRIVATE ${OPENAL_INCLUDE_DIR}) target_link_libraries(test_var PRIVATE ${OPENAL_LIBRARY}) add_test(NAME test_var COMMAND test_var) + +# OpenAL has been deprecated on macOS since Catalina (10.15) +if(APPLE) + target_compile_options(test_tgt PRIVATE "-Wno-deprecated-declarations") + target_compile_options(test_var PRIVATE "-Wno-deprecated-declarations") +endif() diff --git a/Tests/FindOpenAL/Test/main.cxx b/Tests/FindOpenAL/Test/main.cxx index bb45faf..1396c60 100644 --- a/Tests/FindOpenAL/Test/main.cxx +++ b/Tests/FindOpenAL/Test/main.cxx @@ -1,5 +1,10 @@ -#include <AL/al.h> -#include <AL/alc.h> +#ifdef __APPLE__ +# include "OpenAL/al.h" +# include "OpenAL/alc.h" +#else +# include <AL/al.h> +# include <AL/alc.h> +#endif #include <stdio.h> int main() diff --git a/Tests/FindOpenCL/Test/CMakeLists.txt b/Tests/FindOpenCL/Test/CMakeLists.txt index f8a6587..4a1f6bd 100644 --- a/Tests/FindOpenCL/Test/CMakeLists.txt +++ b/Tests/FindOpenCL/Test/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.4) +cmake_minimum_required(VERSION 3.5) project(TestFindOpenCL C) include(CTest) diff --git a/Tests/FindOpenGL/Test/CMakeLists.txt b/Tests/FindOpenGL/Test/CMakeLists.txt index 9004a98..7c805c0 100644 --- a/Tests/FindOpenGL/Test/CMakeLists.txt +++ b/Tests/FindOpenGL/Test/CMakeLists.txt @@ -44,28 +44,115 @@ else() add_test(NAME test_comp_glx_novnd COMMAND test_comp_glx_novnd) endif() -# EGL is only available on Linux+GLVND at present. -if(OpenGL_TEST_VND) - find_package(OpenGL COMPONENTS OpenGL EGL) - if(OpenGL_EGL_FOUND) - add_executable(test_comp_egl main.c) - target_link_libraries(test_comp_egl PRIVATE OpenGL::OpenGL OpenGL::EGL) - add_test(NAME test_comp_egl COMMAND test_comp_egl) - # EGL-only code should not link to GLX. - execute_process(COMMAND ldd test_comp_egl - OUTPUT_VARIABLE LDD_OUT - ERROR_VARIABLE LDD_ERR) - if("${LDD_OUT}" MATCHES "GLX") - message(FATAL_ERROR "EGL-only code links to GLX!") - endif() +find_package(OpenGL COMPONENTS OpenGL EGL) +if(OpenGL_EGL_FOUND) + add_executable(test_comp_egl main.c) + target_link_libraries(test_comp_egl PRIVATE OpenGL::OpenGL OpenGL::EGL) + add_test(NAME test_comp_egl COMMAND test_comp_egl) + # EGL-only code should not link to GLX. + get_target_property(iface_libs OpenGL::EGL INTERFACE_LINK_LIBRARIES) + if(iface_libs MATCHES "GLX") + message(FATAL_ERROR "EGL-only code links to GLX!") + endif() +endif() + +# all three COMPONENTS together. +find_package(OpenGL COMPONENTS OpenGL EGL GLX) +if(OpenGL_EGL_FOUND AND OpenGL_GLX_FOUND) + add_executable(test_comp_both main.c) + target_link_libraries(test_comp_both PRIVATE OpenGL::OpenGL OpenGL::EGL + OpenGL::GLX) + add_test(NAME test_comp_both COMMAND test_comp_both) +endif() + +find_package(OpenGL COMPONENTS GLES2) +if(OpenGL_GLES2_FOUND) + add_executable(test_comp_gles2 main_gles2.c) + target_link_libraries(test_comp_gles2 PRIVATE OpenGL::GLES2) + add_test(NAME test_comp_gles2 COMMAND test_comp_gles2) + # GLES2-only code should not link to OpenGL + get_target_property(iface_libs test_comp_gles2 LINK_LIBRARIES) + if(iface_libs MATCHES "OpenGL::OpenGL") + message(FATAL_ERROR "GLES2-only code links to OpenGL!") endif() +endif() + +# GLES2 and EGL together. +find_package(OpenGL COMPONENTS GLES2 EGL) +if(OpenGL_GLES2_FOUND AND OpenGL_EGL_FOUND) + add_executable(test_comp_gles2_egl main_gles2.c) + target_link_libraries(test_comp_gles2_egl PRIVATE OpenGL::GLES2 + OpenGL::EGL) + add_test(NAME test_comp_gles2_egl COMMAND test_comp_gles2_egl) + # GLES2-EGL-only code should not link to OpenGL or GLX + get_target_property(iface_libs test_comp_gles2_egl LINK_LIBRARIES) + if(iface_libs MATCHES "OpenGL::OpenGL") + message(FATAL_ERROR "GLES2-only code links to OpenGL!") + endif() + if(iface_libs MATCHES "GLX") + message(FATAL_ERROR "GLES2-EGL-only code links to GLX!") + endif() +endif() - # all three COMPONENTS together. - find_package(OpenGL COMPONENTS OpenGL EGL GLX) - if(OpenGL_EGL_FOUND AND OpenGL_GLX_FOUND) - add_executable(test_comp_both main.c) - target_link_libraries(test_comp_both PRIVATE OpenGL::OpenGL OpenGL::EGL - OpenGL::GLX) - add_test(NAME test_comp_both COMMAND test_comp_both) +# GLES2 and GLX together. +find_package(OpenGL COMPONENTS GLES2 GLX) +if(OpenGL_GLES2_FOUND AND OpenGL_GLX_FOUND) + add_executable(test_comp_gles2_glx main_gles2.c) + target_link_libraries(test_comp_gles2_glx PRIVATE OpenGL::GLES2 + OpenGL::GLX) + add_test(NAME test_comp_gles2_glx COMMAND test_comp_gles2_glx) + # GLES2-GLX-only code should not link to OpenGL or EGL + get_target_property(iface_libs test_comp_gles2_glx LINK_LIBRARIES) + if(iface_libs MATCHES "OpenGL::OpenGL") + message(FATAL_ERROR "GLES2-only code links to OpenGL!") + endif() + if(iface_libs MATCHES "EGL") + message(FATAL_ERROR "GLES2-GLX-only code links to EGL!") + endif() +endif() + +find_package(OpenGL COMPONENTS GLES3) +if(OpenGL_GLES3_FOUND) + add_executable(test_comp_gles3 main_gles3.c) + target_link_libraries(test_comp_gles3 PRIVATE OpenGL::GLES3) + add_test(NAME test_comp_gles3 COMMAND test_comp_gles3) + # GLES3-only code should not link to OpenGL. + get_target_property(iface_libs test_comp_gles3 LINK_LIBRARIES) + if(iface_libs MATCHES "OpenGL::OpenGL") + message(FATAL_ERROR "GLES3-only code links to OpenGL!") + endif() +endif() + +# GLES3 and EGL together. +find_package(OpenGL COMPONENTS GLES3 EGL) +if(OpenGL_GLES3_FOUND AND OpenGL_EGL_FOUND) + add_executable(test_comp_gles3_egl main_gles3.c) + target_link_libraries(test_comp_gles3_egl PRIVATE OpenGL::GLES3 + OpenGL::EGL) + add_test(NAME test_comp_gles3_egl COMMAND test_comp_gles3_egl) + # GLES3-EGL-only code should not link to OpenGL or GLX + get_target_property(iface_libs test_comp_gles3_egl LINK_LIBRARIES) + if(iface_libs MATCHES "OpenGL::OpenGL") + message(FATAL_ERROR "GLES3-only code links to OpenGL!") + endif() + if(iface_libs MATCHES "GLX") + message(FATAL_ERROR "GLES3-EGL-only code links to GLX!") + endif() +endif() + +# GLES3 and GLX together. +find_package(OpenGL COMPONENTS GLES3 GLX) +if(OpenGL_GLES3_FOUND AND OpenGL_GLX_FOUND) + add_executable(test_comp_gles3_glx main_gles3.c) + target_link_libraries(test_comp_gles3_glx PRIVATE OpenGL::GLES3 + OpenGL::GLX) + add_test(NAME test_comp_gles3_glx COMMAND test_comp_gles3_glx) + # GLESr-GLX-only code should not link to OpenGL or EGL + get_target_property(iface_libs test_comp_gles3_glx LINK_LIBRARIES) + if(iface_libs MATCHES "OpenGL::OpenGL") + message(FATAL_ERROR "GLES3-only code links to OpenGL!") + endif() + if(iface_libs MATCHES "EGL") + message(FATAL_ERROR "GLES3-GLX-only code links to EGL!") endif() endif() diff --git a/Tests/FindOpenGL/Test/main_gles2.c b/Tests/FindOpenGL/Test/main_gles2.c new file mode 100644 index 0000000..52f5936 --- /dev/null +++ b/Tests/FindOpenGL/Test/main_gles2.c @@ -0,0 +1,17 @@ +#ifdef _WIN32 +# error "GLES2 cannot be tested on WIN32 platforms." +#endif +#ifdef __APPLE__ +# error "GLES2 cannot be tested on macOS platform." +#else +# include <GLES2/gl2.h> +#endif + +#include <stdio.h> + +int main() +{ + /* Reference a GL symbol without requiring a context at runtime. */ + printf("&glGetString = %p\n", &glGetString); + return 0; +} diff --git a/Tests/FindOpenGL/Test/main_gles3.c b/Tests/FindOpenGL/Test/main_gles3.c new file mode 100644 index 0000000..875f73c --- /dev/null +++ b/Tests/FindOpenGL/Test/main_gles3.c @@ -0,0 +1,17 @@ +#ifdef _WIN32 +# error "GLES3 cannot be tested on WIN32 platforms." +#endif +#ifdef __APPLE__ +# error "GLES3 cannot be tested on macOS platform." +#else +# include <GLES3/gl3.h> +#endif + +#include <stdio.h> + +int main() +{ + /* Reference a GL symbol without requiring a context at runtime. */ + printf("&glGetString = %p\n", &glGetString); + return 0; +} diff --git a/Tests/FindOpenSP/Test/CMakeLists.txt b/Tests/FindOpenSP/Test/CMakeLists.txt index d8992d9..266a459 100644 --- a/Tests/FindOpenSP/Test/CMakeLists.txt +++ b/Tests/FindOpenSP/Test/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.4) +cmake_minimum_required(VERSION 3.5) project(TestFindOpenSP CXX) include(CTest) diff --git a/Tests/FindOpenSSL/rand/CMakeLists.txt b/Tests/FindOpenSSL/rand/CMakeLists.txt index 520d5d2..c443221 100644 --- a/Tests/FindOpenSSL/rand/CMakeLists.txt +++ b/Tests/FindOpenSSL/rand/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.0) +cmake_minimum_required(VERSION 3.5) project(FindOpenSSL_rand CXX) include(CTest) diff --git a/Tests/FindPNG/Test/CMakeLists.txt b/Tests/FindPNG/Test/CMakeLists.txt index ad50011..66cdda1 100644 --- a/Tests/FindPNG/Test/CMakeLists.txt +++ b/Tests/FindPNG/Test/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.4) +cmake_minimum_required(VERSION 3.5) project(TestFindPNG C) include(CTest) diff --git a/Tests/FindPython/ArtifactsInteractive/CMakeLists.txt b/Tests/FindPython/ArtifactsInteractive/CMakeLists.txt index 524be92..99823a6 100644 --- a/Tests/FindPython/ArtifactsInteractive/CMakeLists.txt +++ b/Tests/FindPython/ArtifactsInteractive/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.1) +cmake_minimum_required(VERSION 3.5) project(TestArtifactsInteractive LANGUAGES C) diff --git a/Tests/FindPython/CustomFailureMessage/CMakeLists.txt b/Tests/FindPython/CustomFailureMessage/CMakeLists.txt index a0d8eb2..283aeec 100644 --- a/Tests/FindPython/CustomFailureMessage/CMakeLists.txt +++ b/Tests/FindPython/CustomFailureMessage/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.1) +cmake_minimum_required(VERSION 3.5) project(TestCustomFailureMessage LANGUAGES NONE) diff --git a/Tests/FindPython/CustomFailureMessage/Check/CMakeLists.txt b/Tests/FindPython/CustomFailureMessage/Check/CMakeLists.txt index 2164ac1..0fb3036 100644 --- a/Tests/FindPython/CustomFailureMessage/Check/CMakeLists.txt +++ b/Tests/FindPython/CustomFailureMessage/Check/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.1) +cmake_minimum_required(VERSION 3.5) project(TestCustomFailureMessage.Check LANGUAGES NONE) diff --git a/Tests/FindPython/DifferentComponents/CMakeLists.txt b/Tests/FindPython/DifferentComponents/CMakeLists.txt index 7476632..e3e7b36 100644 --- a/Tests/FindPython/DifferentComponents/CMakeLists.txt +++ b/Tests/FindPython/DifferentComponents/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.1) +cmake_minimum_required(VERSION 3.5) project(TestDifferentComponents LANGUAGES C) diff --git a/Tests/FindPython/ExactVersion/CMakeLists.txt b/Tests/FindPython/ExactVersion/CMakeLists.txt index 60abb26..1bd94c4 100644 --- a/Tests/FindPython/ExactVersion/CMakeLists.txt +++ b/Tests/FindPython/ExactVersion/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.1) +cmake_minimum_required(VERSION 3.5) project(TestExactVersion LANGUAGES C) diff --git a/Tests/FindPython/Implementation/CMakeLists.txt b/Tests/FindPython/Implementation/CMakeLists.txt index 592329b..8086c16 100644 --- a/Tests/FindPython/Implementation/CMakeLists.txt +++ b/Tests/FindPython/Implementation/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.1) +cmake_minimum_required(VERSION 3.5) project(TestImplementation${Python_REQUESTED_IMPLEMENTATION} LANGUAGES NONE) diff --git a/Tests/FindPython/IronPython/CMakeLists.txt b/Tests/FindPython/IronPython/CMakeLists.txt index 47ca022..fd3182e 100644 --- a/Tests/FindPython/IronPython/CMakeLists.txt +++ b/Tests/FindPython/IronPython/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.1) +cmake_minimum_required(VERSION 3.5) project(TestIronPython LANGUAGES NONE) diff --git a/Tests/FindPython/IronPython2/CMakeLists.txt b/Tests/FindPython/IronPython2/CMakeLists.txt index fd9d947..b623972 100644 --- a/Tests/FindPython/IronPython2/CMakeLists.txt +++ b/Tests/FindPython/IronPython2/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.1) +cmake_minimum_required(VERSION 3.5) project(TestIronPython2 LANGUAGES NONE) diff --git a/Tests/FindPython/MultiplePackages/CMakeLists.txt b/Tests/FindPython/MultiplePackages/CMakeLists.txt index 5c85155..4845035 100644 --- a/Tests/FindPython/MultiplePackages/CMakeLists.txt +++ b/Tests/FindPython/MultiplePackages/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.1) +cmake_minimum_required(VERSION 3.5) project(TestMultiplePackages C) diff --git a/Tests/FindPython/NumPy/CMakeLists.txt b/Tests/FindPython/NumPy/CMakeLists.txt index 3e17f68..9920336 100644 --- a/Tests/FindPython/NumPy/CMakeLists.txt +++ b/Tests/FindPython/NumPy/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.1) +cmake_minimum_required(VERSION 3.5) project(TestNumPy LANGUAGES C) diff --git a/Tests/FindPython/NumPyOnly/CMakeLists.txt b/Tests/FindPython/NumPyOnly/CMakeLists.txt index bedc627..9aa1bcf 100644 --- a/Tests/FindPython/NumPyOnly/CMakeLists.txt +++ b/Tests/FindPython/NumPyOnly/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.1) +cmake_minimum_required(VERSION 3.5) project(TestNumPyOnly LANGUAGES C) diff --git a/Tests/FindPython/PyPy/CMakeLists.txt b/Tests/FindPython/PyPy/CMakeLists.txt index 4cf7c0a..dfc22d8 100644 --- a/Tests/FindPython/PyPy/CMakeLists.txt +++ b/Tests/FindPython/PyPy/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.1) +cmake_minimum_required(VERSION 3.5) project(TestPyPy LANGUAGES C) diff --git a/Tests/FindPython/PyPy2/CMakeLists.txt b/Tests/FindPython/PyPy2/CMakeLists.txt index ebfc9ab..5b7ce30 100644 --- a/Tests/FindPython/PyPy2/CMakeLists.txt +++ b/Tests/FindPython/PyPy2/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.1) +cmake_minimum_required(VERSION 3.5) project(TestPyPy2 LANGUAGES C) diff --git a/Tests/FindPython/PyPy3/CMakeLists.txt b/Tests/FindPython/PyPy3/CMakeLists.txt index bf7cd61..b702c99 100644 --- a/Tests/FindPython/PyPy3/CMakeLists.txt +++ b/Tests/FindPython/PyPy3/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.1) +cmake_minimum_required(VERSION 3.5) project(TestPyPy3 LANGUAGES C) diff --git a/Tests/FindPython/Python/CMakeLists.txt b/Tests/FindPython/Python/CMakeLists.txt index 9bec22f..85b1711 100644 --- a/Tests/FindPython/Python/CMakeLists.txt +++ b/Tests/FindPython/Python/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.1) +cmake_minimum_required(VERSION 3.5) project(TestPython LANGUAGES C) diff --git a/Tests/FindPython/Python2/CMakeLists.txt b/Tests/FindPython/Python2/CMakeLists.txt index 39577b2..95ed495 100644 --- a/Tests/FindPython/Python2/CMakeLists.txt +++ b/Tests/FindPython/Python2/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.1) +cmake_minimum_required(VERSION 3.5) project(TestPython2 LANGUAGES C) diff --git a/Tests/FindPython/Python2Embedded/CMakeLists.txt b/Tests/FindPython/Python2Embedded/CMakeLists.txt index a1036ce..d9b2d22 100644 --- a/Tests/FindPython/Python2Embedded/CMakeLists.txt +++ b/Tests/FindPython/Python2Embedded/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.1) +cmake_minimum_required(VERSION 3.5) project(TestPython2Embedded LANGUAGES C) diff --git a/Tests/FindPython/Python2Fail/CMakeLists.txt b/Tests/FindPython/Python2Fail/CMakeLists.txt index 989688f..7a6520d 100644 --- a/Tests/FindPython/Python2Fail/CMakeLists.txt +++ b/Tests/FindPython/Python2Fail/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.1) +cmake_minimum_required(VERSION 3.5) project(TestPython2Fail C) diff --git a/Tests/FindPython/Python2Module/CMakeLists.txt b/Tests/FindPython/Python2Module/CMakeLists.txt index c9d46ac..7334d7a 100644 --- a/Tests/FindPython/Python2Module/CMakeLists.txt +++ b/Tests/FindPython/Python2Module/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.1) +cmake_minimum_required(VERSION 3.5) project(TestPython2Module LANGUAGES C) diff --git a/Tests/FindPython/Python2SABIModule/CMakeLists.txt b/Tests/FindPython/Python2SABIModule/CMakeLists.txt index 4f01197..ffbaa33 100644 --- a/Tests/FindPython/Python2SABIModule/CMakeLists.txt +++ b/Tests/FindPython/Python2SABIModule/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.1) +cmake_minimum_required(VERSION 3.5) project(TestPython2SABIModule LANGUAGES C) diff --git a/Tests/FindPython/Python3/CMakeLists.txt b/Tests/FindPython/Python3/CMakeLists.txt index e40557d..42d31f2 100644 --- a/Tests/FindPython/Python3/CMakeLists.txt +++ b/Tests/FindPython/Python3/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.1) +cmake_minimum_required(VERSION 3.5) project(TestPython3 LANGUAGES C) diff --git a/Tests/FindPython/Python3Embedded/CMakeLists.txt b/Tests/FindPython/Python3Embedded/CMakeLists.txt index c45bd8c..1d362be 100644 --- a/Tests/FindPython/Python3Embedded/CMakeLists.txt +++ b/Tests/FindPython/Python3Embedded/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.1) +cmake_minimum_required(VERSION 3.5) project(TestPython3Embedded LANGUAGES C) diff --git a/Tests/FindPython/Python3Fail/CMakeLists.txt b/Tests/FindPython/Python3Fail/CMakeLists.txt index cd46c88..5eca0cb 100644 --- a/Tests/FindPython/Python3Fail/CMakeLists.txt +++ b/Tests/FindPython/Python3Fail/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.1) +cmake_minimum_required(VERSION 3.5) project(TestPython3Fail C) diff --git a/Tests/FindPython/Python3Module/CMakeLists.txt b/Tests/FindPython/Python3Module/CMakeLists.txt index ccc1fdb..57c0ddf 100644 --- a/Tests/FindPython/Python3Module/CMakeLists.txt +++ b/Tests/FindPython/Python3Module/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.1) +cmake_minimum_required(VERSION 3.5) project(TestPython3Module LANGUAGES C) diff --git a/Tests/FindPython/Python3SABIModule/CMakeLists.txt b/Tests/FindPython/Python3SABIModule/CMakeLists.txt index 2a067d0..e045b69 100644 --- a/Tests/FindPython/Python3SABIModule/CMakeLists.txt +++ b/Tests/FindPython/Python3SABIModule/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.1) +cmake_minimum_required(VERSION 3.7) project(TestPython3SABIModule LANGUAGES C) @@ -35,12 +35,16 @@ if(NOT TARGET Python3::SABIModule) message(SEND_ERROR "Python3::SABIModule not found") endif() +if (Python3_VERSION VERSION_GREATER_EQUAL "3.2" AND NOT Python3_SOSABI) + message(FATAL_ERROR "Python3_SOSABI unexpectedly not defined") +endif() + Python3_add_library (spam3 MODULE USE_SABI 3 WITH_SOABI ../spam.c) target_compile_definitions (spam3 PRIVATE PYTHON3) if (Python3_SOSABI) get_property (suffix TARGET spam3 PROPERTY SUFFIX) - if (NOT suffix MATCHES "^.${Python3_SOSABI}") + if (NOT suffix MATCHES "^\\.${Python3_SOSABI}") message(FATAL_ERROR "Module suffix do not include Python3_SOSABI") endif() endif() diff --git a/Tests/FindPython/RequiredArtifacts/CMakeLists.txt b/Tests/FindPython/RequiredArtifacts/CMakeLists.txt index 42d282d..cb9d4d3 100644 --- a/Tests/FindPython/RequiredArtifacts/CMakeLists.txt +++ b/Tests/FindPython/RequiredArtifacts/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.1) +cmake_minimum_required(VERSION 3.5) project(TestRequiredArtifacts LANGUAGES C) diff --git a/Tests/FindPython/RequiredArtifacts/Check/CMakeLists.txt b/Tests/FindPython/RequiredArtifacts/Check/CMakeLists.txt index bb4f67c..4d9c7c8 100644 --- a/Tests/FindPython/RequiredArtifacts/Check/CMakeLists.txt +++ b/Tests/FindPython/RequiredArtifacts/Check/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.1) +cmake_minimum_required(VERSION 3.5) project(TestRequiredArtifacts.Check LANGUAGES C) diff --git a/Tests/FindPython/SOABI/CMakeLists.txt b/Tests/FindPython/SOABI/CMakeLists.txt index 84f7362..60399d3 100644 --- a/Tests/FindPython/SOABI/CMakeLists.txt +++ b/Tests/FindPython/SOABI/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.1) +cmake_minimum_required(VERSION 3.5) project(TestSOABI LANGUAGES C) diff --git a/Tests/FindPython/VirtualEnv/CMakeLists.txt b/Tests/FindPython/VirtualEnv/CMakeLists.txt index dae3282..e2e5bd2 100644 --- a/Tests/FindPython/VirtualEnv/CMakeLists.txt +++ b/Tests/FindPython/VirtualEnv/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.1) +cmake_minimum_required(VERSION 3.5) project(TestVirtualEnv LANGUAGES NONE) diff --git a/Tests/FindPython/VirtualEnvConda/CMakeLists.txt b/Tests/FindPython/VirtualEnvConda/CMakeLists.txt index 23d208d..2f7c0db 100644 --- a/Tests/FindPython/VirtualEnvConda/CMakeLists.txt +++ b/Tests/FindPython/VirtualEnvConda/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.1) +cmake_minimum_required(VERSION 3.5) project(TestVirtualEnvConda LANGUAGES NONE) diff --git a/Tests/FindSDL/Test/CMakeLists.txt b/Tests/FindSDL/Test/CMakeLists.txt index 61d4f4b..0dd1047 100644 --- a/Tests/FindSDL/Test/CMakeLists.txt +++ b/Tests/FindSDL/Test/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.1) +cmake_minimum_required(VERSION 3.5) project(TestFindSDL C) include(CTest) diff --git a/Tests/FindSQLite3/Test/CMakeLists.txt b/Tests/FindSQLite3/Test/CMakeLists.txt index bcc6ebd..43cdd37 100644 --- a/Tests/FindSQLite3/Test/CMakeLists.txt +++ b/Tests/FindSQLite3/Test/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.4) +cmake_minimum_required(VERSION 3.5) project(TestFindSQLite3 C) include(CTest) diff --git a/Tests/FindTIFF/Test/CMakeLists.txt b/Tests/FindTIFF/Test/CMakeLists.txt index e235db3..54404d0 100644 --- a/Tests/FindTIFF/Test/CMakeLists.txt +++ b/Tests/FindTIFF/Test/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.1) +cmake_minimum_required(VERSION 3.5) project(TestFindTIFF) include(CTest) diff --git a/Tests/FindThreads/C-only/CMakeLists.txt b/Tests/FindThreads/C-only/CMakeLists.txt index ee2a5f9..9bc50a4 100644 --- a/Tests/FindThreads/C-only/CMakeLists.txt +++ b/Tests/FindThreads/C-only/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.3 FATAL_ERROR) +cmake_minimum_required(VERSION 3.5 FATAL_ERROR) project(FindThreads_C-only C) find_package(Threads REQUIRED) diff --git a/Tests/FindThreads/CXX-only/CMakeLists.txt b/Tests/FindThreads/CXX-only/CMakeLists.txt index 3c6cc1e..11ae60c 100644 --- a/Tests/FindThreads/CXX-only/CMakeLists.txt +++ b/Tests/FindThreads/CXX-only/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.3 FATAL_ERROR) +cmake_minimum_required(VERSION 3.5 FATAL_ERROR) project(FindThreads_CXX-only CXX) find_package(Threads REQUIRED) diff --git a/Tests/FindVulkan/Test/CMakeLists.txt b/Tests/FindVulkan/Test/CMakeLists.txt index dfcfc15..7198d22 100644 --- a/Tests/FindVulkan/Test/CMakeLists.txt +++ b/Tests/FindVulkan/Test/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.4) +cmake_minimum_required(VERSION 3.5) cmake_policy(SET CMP0091 NEW) project(TestFindVulkan C CXX) include(CTest) diff --git a/Tests/FindXalanC/Test/CMakeLists.txt b/Tests/FindXalanC/Test/CMakeLists.txt index a8c2a0a..eb45802 100644 --- a/Tests/FindXalanC/Test/CMakeLists.txt +++ b/Tests/FindXalanC/Test/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.1) +cmake_minimum_required(VERSION 3.5) project(TestFindXalanC CXX) include(CTest) diff --git a/Tests/FindXercesC/Test/CMakeLists.txt b/Tests/FindXercesC/Test/CMakeLists.txt index 267c6a9..38ae6e4 100644 --- a/Tests/FindXercesC/Test/CMakeLists.txt +++ b/Tests/FindXercesC/Test/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.1) +cmake_minimum_required(VERSION 3.5) project(TestFindXercesC CXX) include(CTest) diff --git a/Tests/FindwxWidgets/CMakeLists.txt b/Tests/FindwxWidgets/CMakeLists.txt new file mode 100644 index 0000000..b66f838 --- /dev/null +++ b/Tests/FindwxWidgets/CMakeLists.txt @@ -0,0 +1,10 @@ +add_test(NAME FindwxWidgets.Test COMMAND + ${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION> + --build-and-test + "${CMake_SOURCE_DIR}/Tests/FindwxWidgets/Test" + "${CMake_BINARY_DIR}/Tests/FindwxWidgets/Test" + ${build_generator_args} + --build-project TestFindwxWidgets + --build-options ${build_options} + --test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION> + ) diff --git a/Tests/FindwxWidgets/Test/CMakeLists.txt b/Tests/FindwxWidgets/Test/CMakeLists.txt new file mode 100644 index 0000000..ecc9c36 --- /dev/null +++ b/Tests/FindwxWidgets/Test/CMakeLists.txt @@ -0,0 +1,17 @@ +cmake_minimum_required(VERSION 3.26) +project(TestFindwxWidgets CXX) +include(CTest) + +find_package(wxWidgets REQUIRED) + +add_executable(test_tgt main.cpp) +target_link_libraries(test_tgt wxWidgets::wxWidgets) +add_test(NAME test_tgt COMMAND test_tgt) + +add_executable(test_var main.cpp) +target_link_libraries(test_var PRIVATE ${wxWidgets_LIBRARIES}) +target_link_directories(test_var PRIVATE ${wxWidgets_LIBRARY_DIRS}) +target_include_directories(test_var PRIVATE ${wxWidgets_INCLUDE_DIRS}) +target_compile_options(test_var PRIVATE ${wxWidgets_CONFIG_OPTIONS}) +target_compile_definitions(test_var PRIVATE ${wxWidgets_DEFINITIONS}) +add_test(NAME test_var COMMAND test_var) diff --git a/Tests/FindwxWidgets/Test/main.cpp b/Tests/FindwxWidgets/Test/main.cpp new file mode 100644 index 0000000..0e576cf --- /dev/null +++ b/Tests/FindwxWidgets/Test/main.cpp @@ -0,0 +1,7 @@ +#include <wx/filefn.h> + +int main() +{ + wxGetCwd(); + return 0; +} diff --git a/Tests/FortranModules/Executable/CMakeLists.txt b/Tests/FortranModules/Executable/CMakeLists.txt index f31a3e6..182e23a 100644 --- a/Tests/FortranModules/Executable/CMakeLists.txt +++ b/Tests/FortranModules/Executable/CMakeLists.txt @@ -6,3 +6,4 @@ add_executable(subdir_exe2 main.f90) target_link_libraries(subdir_exe2 subdir_mods subdir_mods2) add_dependencies(subdir_exe2 ExternalTarget) target_link_libraries(subdir_exe2 myext) +target_link_libraries(subdir_exe2 cycleA) diff --git a/Tests/FortranModules/Executable/main.f90 b/Tests/FortranModules/Executable/main.f90 index 640259c..218eee6 100644 --- a/Tests/FortranModules/Executable/main.f90 +++ b/Tests/FortranModules/Executable/main.f90 @@ -3,5 +3,9 @@ PROGRAM MAINF90 USE libraryModuleB USE subdirModuleA USE externalMod + USE libraryCycleA + USE libraryCycleB CALL printExtModGreeting + CALL libraryCycleA2 + CALL libraryCycleB2 END PROGRAM MAINF90 diff --git a/Tests/FortranModules/Library/CMakeLists.txt b/Tests/FortranModules/Library/CMakeLists.txt index 17438ca..e525208 100644 --- a/Tests/FortranModules/Library/CMakeLists.txt +++ b/Tests/FortranModules/Library/CMakeLists.txt @@ -3,9 +3,14 @@ add_library(subdir_mods a.f90 b.f90) add_executable(subdir_exe main.f90) target_link_libraries(subdir_exe subdir_mods) +add_library(cycleA STATIC cycleA1.f90 cycleA2.f90) +add_library(cycleB STATIC cycleB1.f90 cycleB2.f90) +target_link_libraries(cycleA PRIVATE cycleB) +target_link_libraries(cycleB PRIVATE cycleA) + # Test module output directory if available. if(CMAKE_Fortran_MODDIR_FLAG) - set_target_properties(subdir_mods PROPERTIES + set_target_properties(subdir_mods cycleA cycleB PROPERTIES Fortran_MODULE_DIRECTORY modules ) endif() diff --git a/Tests/FortranModules/Library/cycleA1.f90 b/Tests/FortranModules/Library/cycleA1.f90 new file mode 100644 index 0000000..cceebe2 --- /dev/null +++ b/Tests/FortranModules/Library/cycleA1.f90 @@ -0,0 +1,3 @@ +subroutine cycleA1 +use libraryCycleA +end subroutine diff --git a/Tests/FortranModules/Library/cycleA2.f90 b/Tests/FortranModules/Library/cycleA2.f90 new file mode 100644 index 0000000..a2e432e --- /dev/null +++ b/Tests/FortranModules/Library/cycleA2.f90 @@ -0,0 +1,5 @@ +module libraryCycleA +contains + subroutine libraryCycleA2 + end subroutine +end module diff --git a/Tests/FortranModules/Library/cycleB1.f90 b/Tests/FortranModules/Library/cycleB1.f90 new file mode 100644 index 0000000..d6680fa --- /dev/null +++ b/Tests/FortranModules/Library/cycleB1.f90 @@ -0,0 +1,3 @@ +subroutine cycleB1 +use libraryCycleB +end subroutine diff --git a/Tests/FortranModules/Library/cycleB2.f90 b/Tests/FortranModules/Library/cycleB2.f90 new file mode 100644 index 0000000..07c774e --- /dev/null +++ b/Tests/FortranModules/Library/cycleB2.f90 @@ -0,0 +1,5 @@ +module libraryCycleB +contains + subroutine libraryCycleB2 + end subroutine +end module diff --git a/Tests/QtAutogen/GlobalAutogenExecutable/CMakeLists.txt b/Tests/QtAutogen/GlobalAutogenExecutable/CMakeLists.txt new file mode 100644 index 0000000..34da744 --- /dev/null +++ b/Tests/QtAutogen/GlobalAutogenExecutable/CMakeLists.txt @@ -0,0 +1,30 @@ +cmake_minimum_required(VERSION 3.26) +project(GlobalAutogenExecutable) + +include("../AutogenCoreTest.cmake") + +set(test_automoc_path "global_automoc_exe_path") +set(test_autouic_path "global_autouic_exe_path") +set(test_autorcc_path "global_autorcc_exe_path") + +set(CMAKE_AUTOMOC_EXECUTABLE ${test_automoc_path}) +set(CMAKE_AUTOUIC_EXECUTABLE ${test_autouic_path}) +set(CMAKE_AUTORCC_EXECUTABLE ${test_autorcc_path}) + +add_executable(autogen_test main.cpp) + +get_target_property(target_automoc_path autogen_test AUTOMOC_EXECUTABLE) +get_target_property(target_autouic_path autogen_test AUTOUIC_EXECUTABLE) +get_target_property(target_autorcc_path autogen_test AUTORCC_EXECUTABLE) + +if(NOT ${target_automoc_path} STREQUAL ${test_automoc_path}) + message(FATAL_ERROR "CMAKE_AUTOMOC_EXECUTABLE not set") +endif() + +if (NOT ${target_autouic_path} STREQUAL ${test_autouic_path}) + message(FATAL_ERROR "CMAKE_AUTOUIC_EXECUTABLE not set") +endif() + +if (NOT ${target_autorcc_path} STREQUAL ${test_autorcc_path}) + message(FATAL_ERROR "CMAKE_AUTORCC_EXECUTABLE not set") +endif() diff --git a/Tests/QtAutogen/GlobalAutogenExecutable/main.cpp b/Tests/QtAutogen/GlobalAutogenExecutable/main.cpp new file mode 100644 index 0000000..f8b643a --- /dev/null +++ b/Tests/QtAutogen/GlobalAutogenExecutable/main.cpp @@ -0,0 +1,4 @@ +int main() +{ + return 0; +} diff --git a/Tests/QtAutogen/Tests.cmake b/Tests/QtAutogen/Tests.cmake index a3c57a5..b507ab5 100644 --- a/Tests/QtAutogen/Tests.cmake +++ b/Tests/QtAutogen/Tests.cmake @@ -4,6 +4,7 @@ ADD_AUTOGEN_TEST(AutogenOriginDependsOn) ADD_AUTOGEN_TEST(AutogenTargetDepends) ADD_AUTOGEN_TEST(Complex QtAutogen) ADD_AUTOGEN_TEST(GlobalAutogenTarget) +ADD_AUTOGEN_TEST(GlobalAutogenExecutable) ADD_AUTOGEN_TEST(LowMinimumVersion lowMinimumVersion) ADD_AUTOGEN_TEST(ManySources manySources) ADD_AUTOGEN_TEST(MocOnly mocOnly) diff --git a/Tests/RunCMake/AddRunCMakeTest.cmake b/Tests/RunCMake/AddRunCMakeTest.cmake new file mode 100644 index 0000000..c0c3bba --- /dev/null +++ b/Tests/RunCMake/AddRunCMakeTest.cmake @@ -0,0 +1,10 @@ +if(NOT DEFINED RunCMake_TEST_SUITE) + message("Usage: ${CMAKE_COMMAND} -DRunCMake_TEST_SUITE=<test name> -P Tests/RunCMake/AddRunCMakeTestSuite.cmake") +else() + include("Source/CMakeVersion.cmake") + set(RunCMake_TEST_DIR "Tests/RunCMake/${RunCMake_TEST_SUITE}") + file(MAKE_DIRECTORY "${RunCMake_TEST_DIR}") + file(WRITE "${RunCMake_TEST_DIR}/CMakeLists.txt" "cmake_minimum_required(VERSION ${CMake_VERSION_MAJOR}.${CMake_VERSION_MINOR})\nproject(\${RunCMake_TEST} NONE)\ninclude(\${RunCMake_TEST}.cmake)\n") + file(WRITE "${RunCMake_TEST_DIR}/RunCMakeTest.cmake" "include(RunCMake)\n\n# Write your test cases below, like so:\n#\n# run_cmake(TestCaseName)\n") + file(APPEND "Tests/RunCMake/CMakeLists.txt" "add_RunCMake_test(${RunCMake_TEST_SUITE})\n") +endif() diff --git a/Tests/RunCMake/AppleSilicon/RunCMakeTest.cmake b/Tests/RunCMake/AppleSilicon/RunCMakeTest.cmake index 39e462e..58c50e0 100644 --- a/Tests/RunCMake/AppleSilicon/RunCMakeTest.cmake +++ b/Tests/RunCMake/AppleSilicon/RunCMakeTest.cmake @@ -10,11 +10,17 @@ function(run_arch case) run_cmake(${case}) unset(RunCMake_TEST_OPTIONS) set(RunCMake_TEST_NO_CLEAN 1) - run_cmake_command(${case}-build ${CMAKE_COMMAND} --build . --config Debug) + set(RunCMake_TEST_OUTPUT_MERGE 1) + run_cmake_command(${case}-build ${CMAKE_COMMAND} --build . --config Debug --verbose) endfunction() run_arch(default) +if(RunCMake_GENERATOR MATCHES "Makefiles|Ninja") + run_arch(default-target-arm64 -DCMAKE_C_COMPILER_TARGET=arm64-apple-macosx) + run_arch(default-target-x86_64 -DCMAKE_C_COMPILER_TARGET=x86_64-apple-macosx) +endif() + run_arch(arm64-var -DCMAKE_APPLE_SILICON_PROCESSOR=arm64) run_arch(x86_64-var -DCMAKE_APPLE_SILICON_PROCESSOR=x86_64) diff --git a/Tests/RunCMake/AppleSilicon/default-target-arm64-build-check.cmake b/Tests/RunCMake/AppleSilicon/default-target-arm64-build-check.cmake new file mode 100644 index 0000000..33ad931 --- /dev/null +++ b/Tests/RunCMake/AppleSilicon/default-target-arm64-build-check.cmake @@ -0,0 +1,5 @@ +if(NOT actual_stdout MATCHES "[ -]-target=arm64-apple-macosx ") + set(RunCMake_TEST_FAILED "No -target=arm64-apple-macosx flag found!") +elseif(actual_stdout MATCHES " (-arch +[^ ]*)") + set(RunCMake_TEST_FAILED "'${CMAKE_MATCH_1}' flag incorrectly found!") +endif() diff --git a/Tests/RunCMake/AppleSilicon/default-target-arm64.cmake b/Tests/RunCMake/AppleSilicon/default-target-arm64.cmake new file mode 100644 index 0000000..8c94020 --- /dev/null +++ b/Tests/RunCMake/AppleSilicon/default-target-arm64.cmake @@ -0,0 +1,5 @@ +enable_language(C) +if(NOT CMAKE_OSX_ARCHITECTURES STREQUAL "") + message(FATAL_ERROR "CMAKE_OSX_ARCHITECTURES is '${CMAKE_OSX_ARCHITECTURES}', not empty ''") +endif() +add_library(arm64 arm64.c) diff --git a/Tests/RunCMake/AppleSilicon/default-target-x86_64-build-check.cmake b/Tests/RunCMake/AppleSilicon/default-target-x86_64-build-check.cmake new file mode 100644 index 0000000..9116ef4 --- /dev/null +++ b/Tests/RunCMake/AppleSilicon/default-target-x86_64-build-check.cmake @@ -0,0 +1,5 @@ +if(NOT actual_stdout MATCHES "[ -]-target=x86_64-apple-macosx ") + set(RunCMake_TEST_FAILED "No -target=x86_64-apple-macosx flag found!") +elseif(actual_stdout MATCHES " (-arch +[^ ]*)") + set(RunCMake_TEST_FAILED "'${CMAKE_MATCH_1}' flag incorrectly found!") +endif() diff --git a/Tests/RunCMake/AppleSilicon/default-target-x86_64.cmake b/Tests/RunCMake/AppleSilicon/default-target-x86_64.cmake new file mode 100644 index 0000000..ded46b7 --- /dev/null +++ b/Tests/RunCMake/AppleSilicon/default-target-x86_64.cmake @@ -0,0 +1,5 @@ +enable_language(C) +if(NOT CMAKE_OSX_ARCHITECTURES STREQUAL "") + message(FATAL_ERROR "CMAKE_OSX_ARCHITECTURES is '${CMAKE_OSX_ARCHITECTURES}', not empty ''") +endif() +add_library(x86_64 x86_64.c) diff --git a/Tests/RunCMake/CMP0115/CMP0115-OLD-stderr.txt b/Tests/RunCMake/CMP0115/CMP0115-OLD-stderr.txt index 8b90311..67d00f7 100644 --- a/Tests/RunCMake/CMP0115/CMP0115-OLD-stderr.txt +++ b/Tests/RunCMake/CMP0115/CMP0115-OLD-stderr.txt @@ -3,11 +3,9 @@ noexist - Tried extensions [^ -]* - [^ -]* -Call Stack \(most recent call first\): + Tried extensions ([^ +]+ +)+Call Stack \(most recent call first\): CMP0115-OLD\.cmake:[0-9]+ \(include\) CMakeLists\.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/CMP0115/CMP0115-WARN-stderr.txt b/Tests/RunCMake/CMP0115/CMP0115-WARN-stderr.txt index 7b100b6..e79ca97 100644 --- a/Tests/RunCMake/CMP0115/CMP0115-WARN-stderr.txt +++ b/Tests/RunCMake/CMP0115/CMP0115-WARN-stderr.txt @@ -17,11 +17,9 @@ CMake Error at CMP0115\.cmake:[0-9]+ \(add_executable\): noexist - Tried extensions [^ -]* - [^ -]* -Call Stack \(most recent call first\): + Tried extensions ([^ +]+ +)+Call Stack \(most recent call first\): CMP0115-WARN\.cmake:[0-9]+ \(include\) CMakeLists\.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt index 0ebb720..080740c 100644 --- a/Tests/RunCMake/CMakeLists.txt +++ b/Tests/RunCMake/CMakeLists.txt @@ -784,6 +784,7 @@ if(DEFINED CMake_COMPILER_FORCES_NEW_DTAGS) endif() add_RunCMake_test(file-GET_RUNTIME_DEPENDENCIES -DCMake_INSTALL_NAME_TOOL_BUG=${CMake_INSTALL_NAME_TOOL_BUG} + -DCMAKE_C_COMPILER_ID=${CMAKE_C_COMPILER_ID} ) add_RunCMake_test(CPackCommandLine) diff --git a/Tests/RunCMake/CheckCompilerFlag/CheckCompilerFlagC.cmake b/Tests/RunCMake/CheckCompilerFlag/CheckCompilerFlagC.cmake index 276158c..64a961e 100644 --- a/Tests/RunCMake/CheckCompilerFlag/CheckCompilerFlagC.cmake +++ b/Tests/RunCMake/CheckCompilerFlag/CheckCompilerFlagC.cmake @@ -18,6 +18,15 @@ if(CMAKE_C_COMPILER_ID MATCHES "GNU|LCC|Clang" AND NOT "x${CMAKE_C_SIMULATE_ID}" if(NOT SHOULD_WORK) message(SEND_ERROR "${CMAKE_C_COMPILER_ID} compiler flag '-x c' check failed") endif() + + block() + # Test tolerating a flag that is not used when driving the linker. + string(APPEND CMAKE_C_FLAGS " -nostdinc") + check_compiler_flag(C "-x c" SHOULD_WORK_NOSTDINC) + if(NOT SHOULD_WORK_NOSTDINC) + message(SEND_ERROR "${CMAKE_C_COMPILER_ID} compiler flag '-x c -nostdinc' check failed") + endif() + endblock() endif() if(CMAKE_C_COMPILER_ID STREQUAL "GNU") # LCC C compiler silently ignore -frtti instead of failing, so skip it here. diff --git a/Tests/RunCMake/CheckCompilerFlag/CheckCompilerFlagCXX.cmake b/Tests/RunCMake/CheckCompilerFlag/CheckCompilerFlagCXX.cmake index dec31ec..0026a2a 100644 --- a/Tests/RunCMake/CheckCompilerFlag/CheckCompilerFlagCXX.cmake +++ b/Tests/RunCMake/CheckCompilerFlag/CheckCompilerFlagCXX.cmake @@ -18,6 +18,15 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|LCC|Clang" AND NOT "x${CMAKE_CXX_SIMULATE_ if(NOT SHOULD_WORK) message(SEND_ERROR "${CMAKE_CXX_COMPILER_ID} compiler flag '-x c++' check failed") endif() + + block() + # Test tolerating a flag that is not used when driving the linker. + string(APPEND CMAKE_CXX_FLAGS " -nostdinc++") + check_compiler_flag(CXX "-x c++" SHOULD_WORK_NOSTDINCXX) + if(NOT SHOULD_WORK_NOSTDINCXX) + message(SEND_ERROR "${CMAKE_CXX_COMPILER_ID} compiler flag '-x c++ -nostdinc++' check failed") + endif() + endblock() endif() if(NOT "$ENV{LC_ALL}" STREQUAL "BAD") diff --git a/Tests/RunCMake/ClangTidy/CXX.cmake b/Tests/RunCMake/ClangTidy/CXX.cmake index 2d22325..3214122 100644 --- a/Tests/RunCMake/ClangTidy/CXX.cmake +++ b/Tests/RunCMake/ClangTidy/CXX.cmake @@ -1,3 +1,3 @@ enable_language(CXX) -set(CMAKE_CXX_CLANG_TIDY "${PSEUDO_TIDY}" -some -args) +set(CMAKE_CXX_CLANG_TIDY "$<1:${PSEUDO_TIDY}>" -some -args) add_executable(main main.cxx) diff --git a/Tests/RunCMake/Cppcheck/CXX.cmake b/Tests/RunCMake/Cppcheck/CXX.cmake index 3b79471..7030c61 100644 --- a/Tests/RunCMake/Cppcheck/CXX.cmake +++ b/Tests/RunCMake/Cppcheck/CXX.cmake @@ -1,3 +1,3 @@ enable_language(CXX) -set(CMAKE_CXX_CPPCHECK "${PSEUDO_CPPCHECK}") +set(CMAKE_CXX_CPPCHECK "$<1:${PSEUDO_CPPCHECK}>") add_executable(main main.cxx) diff --git a/Tests/RunCMake/Cpplint/CXX.cmake b/Tests/RunCMake/Cpplint/CXX.cmake index 35f05ee..b58609c 100644 --- a/Tests/RunCMake/Cpplint/CXX.cmake +++ b/Tests/RunCMake/Cpplint/CXX.cmake @@ -1,3 +1,3 @@ enable_language(CXX) -set(CMAKE_CXX_CPPLINT "${PSEUDO_CPPLINT}" --verbose=0 --linelength=80) +set(CMAKE_CXX_CPPLINT "$<1:${PSEUDO_CPPLINT}>" --verbose=0 --linelength=80) add_executable(main main.cxx) diff --git a/Tests/RunCMake/File_Generate/SourceProperty-CMP0070-NEW-stderr.txt b/Tests/RunCMake/File_Generate/SourceProperty-CMP0070-NEW-stderr.txt index f51d05a..b47a137 100644 --- a/Tests/RunCMake/File_Generate/SourceProperty-CMP0070-NEW-stderr.txt +++ b/Tests/RunCMake/File_Generate/SourceProperty-CMP0070-NEW-stderr.txt @@ -3,9 +3,9 @@ .*\/relative-output-NEW\.c - Tried extensions \.c \.C.* -Call Stack \(most recent call first\): + Tried extensions ([^ +]+ +)+Call Stack \(most recent call first\): CMakeLists.txt:[0-9]+ \(include\) - - ++ CMake Generate step failed. Build files cannot be regenerated correctly.$ diff --git a/Tests/RunCMake/File_Generate/SourceProperty-CMP0070-NEW.cmake b/Tests/RunCMake/File_Generate/SourceProperty-CMP0070-NEW.cmake index d2b3e0c..16d5563 100644 --- a/Tests/RunCMake/File_Generate/SourceProperty-CMP0070-NEW.cmake +++ b/Tests/RunCMake/File_Generate/SourceProperty-CMP0070-NEW.cmake @@ -1,5 +1,5 @@ enable_language(C) -add_library(foo) +add_library(foo empty.c) cmake_policy(SET CMP0070 NEW) file(GENERATE OUTPUT relative-output-NEW.c CONTENT "") diff --git a/Tests/RunCMake/File_Generate/SourceProperty-CMP0070-OLD-stderr.txt b/Tests/RunCMake/File_Generate/SourceProperty-CMP0070-OLD-stderr.txt index 07b0026..39735d7 100644 --- a/Tests/RunCMake/File_Generate/SourceProperty-CMP0070-OLD-stderr.txt +++ b/Tests/RunCMake/File_Generate/SourceProperty-CMP0070-OLD-stderr.txt @@ -8,16 +8,15 @@ behavior and not rely on setting a policy to OLD. Call Stack \(most recent call first\): CMakeLists.txt:[0-9]+ \(include\) - - ++ CMake Error at SourceProperty-CMP0070-OLD.cmake:[0-9]+ \(target_sources\): Cannot find source file: .*\/relative-output-OLD\.c - Tried extensions \.c \.C.* -Call Stack \(most recent call first\): + Tried extensions ([^ +]+ +)+Call Stack \(most recent call first\): CMakeLists.txt:[0-9]+ \(include\) - - ++ CMake Generate step failed. Build files cannot be regenerated correctly.$ diff --git a/Tests/RunCMake/File_Generate/SourceProperty-CMP0070-OLD.cmake b/Tests/RunCMake/File_Generate/SourceProperty-CMP0070-OLD.cmake index 48eae1e..4f566b0 100644 --- a/Tests/RunCMake/File_Generate/SourceProperty-CMP0070-OLD.cmake +++ b/Tests/RunCMake/File_Generate/SourceProperty-CMP0070-OLD.cmake @@ -1,5 +1,5 @@ enable_language(C) -add_library(foo) +add_library(foo empty.c) cmake_policy(SET CMP0070 OLD) file(GENERATE OUTPUT relative-output-OLD.c CONTENT "") diff --git a/Tests/RunCMake/Framework/FrameworkConsumption.cmake b/Tests/RunCMake/Framework/FrameworkConsumption.cmake index a1ce006..2180cf9 100644 --- a/Tests/RunCMake/Framework/FrameworkConsumption.cmake +++ b/Tests/RunCMake/Framework/FrameworkConsumption.cmake @@ -22,10 +22,14 @@ set_target_properties(Gui2 PROPERTIES ) add_executable(app2 main2.c) -set_target_properties(Gui2 PROPERTIES - PUBLIC_HEADER "${input_header}" - FRAMEWORK TRUE +set_target_properties(app2 PROPERTIES RUNTIME_OUTPUT_DIRECTORY bin ) target_link_libraries(app2 PRIVATE Gui2) + + +# Same test with STATIC consumer +add_library(Consumer STATIC consumer.c) + +target_link_libraries(Consumer PRIVATE Gui2) diff --git a/Tests/RunCMake/Framework/consumer.c b/Tests/RunCMake/Framework/consumer.c new file mode 100644 index 0000000..a578976 --- /dev/null +++ b/Tests/RunCMake/Framework/consumer.c @@ -0,0 +1,9 @@ + +#include <Gui2/Gui.h> + +int consumer() +{ + foo(); + + return 0; +} diff --git a/Tests/RunCMake/IncludeWhatYouUse/CXX.cmake b/Tests/RunCMake/IncludeWhatYouUse/CXX.cmake index 896930c..8780bb6 100644 --- a/Tests/RunCMake/IncludeWhatYouUse/CXX.cmake +++ b/Tests/RunCMake/IncludeWhatYouUse/CXX.cmake @@ -1,3 +1,3 @@ enable_language(CXX) -set(CMAKE_CXX_INCLUDE_WHAT_YOU_USE "${PSEUDO_IWYU}" -some -args) +set(CMAKE_CXX_INCLUDE_WHAT_YOU_USE "$<1:${PSEUDO_IWYU}>" -some -args) add_executable(main main.cxx) diff --git a/Tests/RunCMake/InterfaceLibrary/global-interface-stderr.txt b/Tests/RunCMake/InterfaceLibrary/global-interface-stderr.txt index 38585eb..352bb68 100644 --- a/Tests/RunCMake/InterfaceLibrary/global-interface-stderr.txt +++ b/Tests/RunCMake/InterfaceLibrary/global-interface-stderr.txt @@ -3,7 +3,7 @@ CMake Error at global-interface.cmake:2 \(add_library\): GLOBAL - Tried extensions \.c \.C .* -.* -Call Stack \(most recent call first\): + Tried extensions ([^ +]+ +)+Call Stack \(most recent call first\): CMakeLists.txt:3 \(include\) diff --git a/Tests/RunCMake/MaxRecursionDepth/RunCMakeTest.cmake b/Tests/RunCMake/MaxRecursionDepth/RunCMakeTest.cmake index c5a859d..fdf418f 100644 --- a/Tests/RunCMake/MaxRecursionDepth/RunCMakeTest.cmake +++ b/Tests/RunCMake/MaxRecursionDepth/RunCMakeTest.cmake @@ -1,26 +1,42 @@ include(RunCMake) include(RunCTest) -function(run_cmake_recursive name) - set(RunCMake_TEST_OPTIONS "-DCMAKE_MODULE_PATH=${CMAKE_CURRENT_LIST_DIR}" -DTEST_NAME=${name}) - run_cmake(${name}-default) - unset(RunCMake_TEST_OPTIONS) - set(RunCMake_TEST_OPTIONS "-DCMAKE_MODULE_PATH=${CMAKE_CURRENT_LIST_DIR}" -DTEST_NAME=${name} -DCMAKE_MAXIMUM_RECURSION_DEPTH=10) - run_cmake(${name}-var) - unset(RunCMake_TEST_OPTIONS) - set(RunCMake_TEST_OPTIONS "-DCMAKE_MODULE_PATH=${CMAKE_CURRENT_LIST_DIR}" -DTEST_NAME=${name} -DCMAKE_MAXIMUM_RECURSION_DEPTH=a) - run_cmake(${name}-invalid-var) - unset(RunCMake_TEST_OPTIONS) +# Isolate this test from the caller's environment. +unset(ENV{CMAKE_MAXIMUM_RECURSION_DEPTH}) +function(run_cmake_recursive name) + run_cmake_with_options(${name}-default "-DCMAKE_MODULE_PATH=${CMAKE_CURRENT_LIST_DIR}" -DTEST_NAME=${name}) run_cmake_command(${name}-default-script ${CMAKE_COMMAND} "-DCMAKE_MODULE_PATH=${CMAKE_CURRENT_LIST_DIR}" -DTEST_NAME=${name} -P "${CMAKE_CURRENT_LIST_DIR}/CMakeLists.txt") + + set(ENV{CMAKE_MAXIMUM_RECURSION_DEPTH} 5) # overridden, not used + run_cmake_with_options(${name}-var "-DCMAKE_MODULE_PATH=${CMAKE_CURRENT_LIST_DIR}" -DTEST_NAME=${name} -DCMAKE_MAXIMUM_RECURSION_DEPTH=10) + run_cmake_with_options(${name}-invalid-var "-DCMAKE_MODULE_PATH=${CMAKE_CURRENT_LIST_DIR}" -DTEST_NAME=${name} -DCMAKE_MAXIMUM_RECURSION_DEPTH=a) run_cmake_command(${name}-var-script ${CMAKE_COMMAND} "-DCMAKE_MODULE_PATH=${CMAKE_CURRENT_LIST_DIR}" -DTEST_NAME=${name} -DCMAKE_MAXIMUM_RECURSION_DEPTH=10 -P "${CMAKE_CURRENT_LIST_DIR}/CMakeLists.txt") run_cmake_command(${name}-invalid-var-script ${CMAKE_COMMAND} "-DCMAKE_MODULE_PATH=${CMAKE_CURRENT_LIST_DIR}" -DTEST_NAME=${name} -DCMAKE_MAXIMUM_RECURSION_DEPTH=a -P "${CMAKE_CURRENT_LIST_DIR}/CMakeLists.txt") + + set(ENV{CMAKE_MAXIMUM_RECURSION_DEPTH} 10) + run_cmake_with_options(${name}-env "-DCMAKE_MODULE_PATH=${CMAKE_CURRENT_LIST_DIR}" -DTEST_NAME=${name}) + run_cmake_command(${name}-env-script ${CMAKE_COMMAND} "-DCMAKE_MODULE_PATH=${CMAKE_CURRENT_LIST_DIR}" -DTEST_NAME=${name} -P "${CMAKE_CURRENT_LIST_DIR}/CMakeLists.txt") + + set(ENV{CMAKE_MAXIMUM_RECURSION_DEPTH} a) + run_cmake_with_options(${name}-invalid-env "-DCMAKE_MODULE_PATH=${CMAKE_CURRENT_LIST_DIR}" -DTEST_NAME=${name}) + run_cmake_command(${name}-invalid-env-script ${CMAKE_COMMAND} "-DCMAKE_MODULE_PATH=${CMAKE_CURRENT_LIST_DIR}" -DTEST_NAME=${name} -P "${CMAKE_CURRENT_LIST_DIR}/CMakeLists.txt") + + unset(ENV{CMAKE_MAXIMUM_RECURSION_DEPTH}) endfunction() function(run_ctest_recursive name) run_ctest(${name}-default "-DCMAKE_MODULE_PATH=${CMAKE_CURRENT_LIST_DIR}" -DTEST_NAME=${name}) run_ctest(${name}-var "-DCMAKE_MODULE_PATH=${CMAKE_CURRENT_LIST_DIR}" -DTEST_NAME=${name} -DCMAKE_MAXIMUM_RECURSION_DEPTH=10) run_ctest(${name}-invalid-var "-DCMAKE_MODULE_PATH=${CMAKE_CURRENT_LIST_DIR}" -DTEST_NAME=${name} -DCMAKE_MAXIMUM_RECURSION_DEPTH=a) + + set(ENV{CMAKE_MAXIMUM_RECURSION_DEPTH} 10) + run_ctest(${name}-env "-DCMAKE_MODULE_PATH=${CMAKE_CURRENT_LIST_DIR}" -DTEST_NAME=${name}) + + set(ENV{CMAKE_MAXIMUM_RECURSION_DEPTH} a) + run_ctest(${name}-invalid-env "-DCMAKE_MODULE_PATH=${CMAKE_CURRENT_LIST_DIR}" -DTEST_NAME=${name}) + + unset(ENV{CMAKE_MAXIMUM_RECURSION_DEPTH}) endfunction() run_cmake_recursive(function) @@ -32,12 +48,8 @@ run_cmake_recursive(variable_watch) # We run these tests separately and only with a small limit because they are # taxing and slow. The "implicit" and "invalid" cases are already thoroughly # covered by the other tests above. -set(RunCMake_TEST_OPTIONS "-DCMAKE_MODULE_PATH=${CMAKE_CURRENT_LIST_DIR}" -DTEST_NAME=add_subdirectory -DCMAKE_MAXIMUM_RECURSION_DEPTH=10) -run_cmake(add_subdirectory-var) -unset(RunCMake_TEST_OPTIONS) -set(RunCMake_TEST_OPTIONS "-DCMAKE_MODULE_PATH=${CMAKE_CURRENT_LIST_DIR}" -DTEST_NAME=try_compile -DCMAKE_MAXIMUM_RECURSION_DEPTH=10) -run_cmake(try_compile-var) -unset(RunCMake_TEST_OPTIONS) +run_cmake_with_options(add_subdirectory-var "-DCMAKE_MODULE_PATH=${CMAKE_CURRENT_LIST_DIR}" -DTEST_NAME=add_subdirectory -DCMAKE_MAXIMUM_RECURSION_DEPTH=10) +run_cmake_with_options(try_compile-var "-DCMAKE_MODULE_PATH=${CMAKE_CURRENT_LIST_DIR}" -DTEST_NAME=try_compile -DCMAKE_MAXIMUM_RECURSION_DEPTH=10) run_ctest_recursive(ctest_read_custom_files) diff --git a/Tests/RunCMake/MaxRecursionDepth/ctest_read_custom_files-env-result.txt b/Tests/RunCMake/MaxRecursionDepth/ctest_read_custom_files-env-result.txt new file mode 100644 index 0000000..b57e2de --- /dev/null +++ b/Tests/RunCMake/MaxRecursionDepth/ctest_read_custom_files-env-result.txt @@ -0,0 +1 @@ +(-1|255) diff --git a/Tests/RunCMake/MaxRecursionDepth/ctest_read_custom_files-env-stderr.txt b/Tests/RunCMake/MaxRecursionDepth/ctest_read_custom_files-env-stderr.txt new file mode 100644 index 0000000..b664fa0 --- /dev/null +++ b/Tests/RunCMake/MaxRecursionDepth/ctest_read_custom_files-env-stderr.txt @@ -0,0 +1,34 @@ +^2 +3 +4 +5 +6 +7 +8 +9 +10 +CMake Error at .*/Tests/RunCMake/MaxRecursionDepth/CTestCustom\.cmake:1 \(message\): + Maximum recursion depth of 10 exceeded +Call Stack \(most recent call first\): + .*/Tests/RunCMake/MaxRecursionDepth/CTestCustom\.cmake:3 \(ctest_read_custom_files\) + .*/Tests/RunCMake/MaxRecursionDepth/CTestCustom\.cmake:3 \(ctest_read_custom_files\) + .*/Tests/RunCMake/MaxRecursionDepth/CTestCustom\.cmake:3 \(ctest_read_custom_files\) + .*/Tests/RunCMake/MaxRecursionDepth/CTestCustom\.cmake:3 \(ctest_read_custom_files\) + .*/Tests/RunCMake/MaxRecursionDepth/CTestCustom\.cmake:3 \(ctest_read_custom_files\) + .*/Tests/RunCMake/MaxRecursionDepth/CTestCustom\.cmake:3 \(ctest_read_custom_files\) + .*/Tests/RunCMake/MaxRecursionDepth/CTestCustom\.cmake:3 \(ctest_read_custom_files\) + .*/Tests/RunCMake/MaxRecursionDepth/CTestCustom\.cmake:3 \(ctest_read_custom_files\) + .*/Tests/RunCMake/MaxRecursionDepth/CTestCustom\.cmake:3 \(ctest_read_custom_files\) + .*/Tests/RunCMake/MaxRecursionDepth/ctest_read_custom_files-env/test\.cmake:10 \(ctest_read_custom_files\) + + +Problem reading custom configuration: .*/Tests/RunCMake/MaxRecursionDepth/CTestCustom\.cmake +Problem reading custom configuration: .*/Tests/RunCMake/MaxRecursionDepth/CTestCustom\.cmake +Problem reading custom configuration: .*/Tests/RunCMake/MaxRecursionDepth/CTestCustom\.cmake +Problem reading custom configuration: .*/Tests/RunCMake/MaxRecursionDepth/CTestCustom\.cmake +Problem reading custom configuration: .*/Tests/RunCMake/MaxRecursionDepth/CTestCustom\.cmake +Problem reading custom configuration: .*/Tests/RunCMake/MaxRecursionDepth/CTestCustom\.cmake +Problem reading custom configuration: .*/Tests/RunCMake/MaxRecursionDepth/CTestCustom\.cmake +Problem reading custom configuration: .*/Tests/RunCMake/MaxRecursionDepth/CTestCustom\.cmake +Problem reading custom configuration: .*/Tests/RunCMake/MaxRecursionDepth/CTestCustom\.cmake +Problem reading custom configuration: .*/Tests/RunCMake/MaxRecursionDepth/CTestCustom\.cmake$ diff --git a/Tests/RunCMake/MaxRecursionDepth/ctest_read_custom_files-invalid-env-result.txt b/Tests/RunCMake/MaxRecursionDepth/ctest_read_custom_files-invalid-env-result.txt new file mode 100644 index 0000000..b57e2de --- /dev/null +++ b/Tests/RunCMake/MaxRecursionDepth/ctest_read_custom_files-invalid-env-result.txt @@ -0,0 +1 @@ +(-1|255) diff --git a/Tests/RunCMake/MaxRecursionDepth/ctest_read_custom_files-invalid-env-stderr.txt b/Tests/RunCMake/MaxRecursionDepth/ctest_read_custom_files-invalid-env-stderr.txt new file mode 100644 index 0000000..7dbbb3e --- /dev/null +++ b/Tests/RunCMake/MaxRecursionDepth/ctest_read_custom_files-invalid-env-stderr.txt @@ -0,0 +1,5 @@ +[0-9]+ +CMake Error at .*/Tests/RunCMake/MaxRecursionDepth/CTestCustom\.cmake:1 \(message\): + Maximum recursion depth of [0-9]+ exceeded +Call Stack \(most recent call first\): + .*/Tests/RunCMake/MaxRecursionDepth/CTestCustom\.cmake:3 \(ctest_read_custom_files\) diff --git a/Tests/RunCMake/MaxRecursionDepth/find_package-default-script-stderr.txt b/Tests/RunCMake/MaxRecursionDepth/find_package-default-script-stderr.txt index b8557ab..4e965e8 100644 --- a/Tests/RunCMake/MaxRecursionDepth/find_package-default-script-stderr.txt +++ b/Tests/RunCMake/MaxRecursionDepth/find_package-default-script-stderr.txt @@ -1,5 +1,7 @@ [0-9]+ -CMake Error at .*/FindRecursivePackage\.cmake:1 \(message\): - Maximum recursion depth of [0-9]+ exceeded +CMake Error at [^ +]*/Tests/RunCMake/MaxRecursionDepth/FindRecursivePackage.cmake:[0-9]+ \(find_package\): + find_package maximum nesting depth of [0-9]+ exceeded. Call Stack \(most recent call first\): - .*/FindRecursivePackage\.cmake:3 \(find_package\) + [^ +]*/Tests/RunCMake/MaxRecursionDepth/FindRecursivePackage.cmake:[0-9]+ \(find_package\) diff --git a/Tests/RunCMake/MaxRecursionDepth/find_package-default-stderr.txt b/Tests/RunCMake/MaxRecursionDepth/find_package-default-stderr.txt index 5d31e29..0119953 100644 --- a/Tests/RunCMake/MaxRecursionDepth/find_package-default-stderr.txt +++ b/Tests/RunCMake/MaxRecursionDepth/find_package-default-stderr.txt @@ -1,5 +1,5 @@ [0-9]+ -CMake Error at FindRecursivePackage\.cmake:1 \(message\): - Maximum recursion depth of [0-9]+ exceeded +CMake Error at FindRecursivePackage.cmake:[0-9]+ \(find_package\): + find_package maximum nesting depth of [0-9]+ exceeded. Call Stack \(most recent call first\): - FindRecursivePackage\.cmake:3 \(find_package\) + FindRecursivePackage.cmake:[0-9]+ \(find_package\) diff --git a/Tests/RunCMake/MaxRecursionDepth/find_package-env-result.txt b/Tests/RunCMake/MaxRecursionDepth/find_package-env-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/MaxRecursionDepth/find_package-env-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/MaxRecursionDepth/find_package-env-script-result.txt b/Tests/RunCMake/MaxRecursionDepth/find_package-env-script-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/MaxRecursionDepth/find_package-env-script-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/MaxRecursionDepth/find_package-env-script-stderr.txt b/Tests/RunCMake/MaxRecursionDepth/find_package-env-script-stderr.txt new file mode 100644 index 0000000..5314551 --- /dev/null +++ b/Tests/RunCMake/MaxRecursionDepth/find_package-env-script-stderr.txt @@ -0,0 +1,21 @@ +^3 +4 +5 +6 +7 +8 +9 +10 +CMake Error at .*/FindRecursivePackage\.cmake:1 \(message\): + Maximum recursion depth of 10 exceeded +Call Stack \(most recent call first\): + .*/FindRecursivePackage\.cmake:3 \(find_package\) + .*/FindRecursivePackage\.cmake:3 \(find_package\) + .*/FindRecursivePackage\.cmake:3 \(find_package\) + .*/FindRecursivePackage\.cmake:3 \(find_package\) + .*/FindRecursivePackage\.cmake:3 \(find_package\) + .*/FindRecursivePackage\.cmake:3 \(find_package\) + .*/FindRecursivePackage\.cmake:3 \(find_package\) + .*/FindRecursivePackage\.cmake:3 \(find_package\) + .*/find_package\.cmake:2 \(find_package\) + .*/CMakeLists\.txt:5 \(include\)$ diff --git a/Tests/RunCMake/MaxRecursionDepth/find_package-env-stderr.txt b/Tests/RunCMake/MaxRecursionDepth/find_package-env-stderr.txt new file mode 100644 index 0000000..b47a13a --- /dev/null +++ b/Tests/RunCMake/MaxRecursionDepth/find_package-env-stderr.txt @@ -0,0 +1,21 @@ +^3 +4 +5 +6 +7 +8 +9 +10 +CMake Error at FindRecursivePackage\.cmake:1 \(message\): + Maximum recursion depth of 10 exceeded +Call Stack \(most recent call first\): + FindRecursivePackage\.cmake:3 \(find_package\) + FindRecursivePackage\.cmake:3 \(find_package\) + FindRecursivePackage\.cmake:3 \(find_package\) + FindRecursivePackage\.cmake:3 \(find_package\) + FindRecursivePackage\.cmake:3 \(find_package\) + FindRecursivePackage\.cmake:3 \(find_package\) + FindRecursivePackage\.cmake:3 \(find_package\) + FindRecursivePackage\.cmake:3 \(find_package\) + find_package\.cmake:2 \(find_package\) + CMakeLists\.txt:5 \(include\)$ diff --git a/Tests/RunCMake/MaxRecursionDepth/find_package-invalid-env-result.txt b/Tests/RunCMake/MaxRecursionDepth/find_package-invalid-env-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/MaxRecursionDepth/find_package-invalid-env-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/MaxRecursionDepth/find_package-invalid-env-script-result.txt b/Tests/RunCMake/MaxRecursionDepth/find_package-invalid-env-script-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/MaxRecursionDepth/find_package-invalid-env-script-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/MaxRecursionDepth/find_package-invalid-env-script-stderr.txt b/Tests/RunCMake/MaxRecursionDepth/find_package-invalid-env-script-stderr.txt new file mode 100644 index 0000000..4e965e8 --- /dev/null +++ b/Tests/RunCMake/MaxRecursionDepth/find_package-invalid-env-script-stderr.txt @@ -0,0 +1,7 @@ +[0-9]+ +CMake Error at [^ +]*/Tests/RunCMake/MaxRecursionDepth/FindRecursivePackage.cmake:[0-9]+ \(find_package\): + find_package maximum nesting depth of [0-9]+ exceeded. +Call Stack \(most recent call first\): + [^ +]*/Tests/RunCMake/MaxRecursionDepth/FindRecursivePackage.cmake:[0-9]+ \(find_package\) diff --git a/Tests/RunCMake/MaxRecursionDepth/find_package-invalid-env-stderr.txt b/Tests/RunCMake/MaxRecursionDepth/find_package-invalid-env-stderr.txt new file mode 100644 index 0000000..0119953 --- /dev/null +++ b/Tests/RunCMake/MaxRecursionDepth/find_package-invalid-env-stderr.txt @@ -0,0 +1,5 @@ +[0-9]+ +CMake Error at FindRecursivePackage.cmake:[0-9]+ \(find_package\): + find_package maximum nesting depth of [0-9]+ exceeded. +Call Stack \(most recent call first\): + FindRecursivePackage.cmake:[0-9]+ \(find_package\) diff --git a/Tests/RunCMake/MaxRecursionDepth/find_package-invalid-var-script-stderr.txt b/Tests/RunCMake/MaxRecursionDepth/find_package-invalid-var-script-stderr.txt index b8557ab..4e965e8 100644 --- a/Tests/RunCMake/MaxRecursionDepth/find_package-invalid-var-script-stderr.txt +++ b/Tests/RunCMake/MaxRecursionDepth/find_package-invalid-var-script-stderr.txt @@ -1,5 +1,7 @@ [0-9]+ -CMake Error at .*/FindRecursivePackage\.cmake:1 \(message\): - Maximum recursion depth of [0-9]+ exceeded +CMake Error at [^ +]*/Tests/RunCMake/MaxRecursionDepth/FindRecursivePackage.cmake:[0-9]+ \(find_package\): + find_package maximum nesting depth of [0-9]+ exceeded. Call Stack \(most recent call first\): - .*/FindRecursivePackage\.cmake:3 \(find_package\) + [^ +]*/Tests/RunCMake/MaxRecursionDepth/FindRecursivePackage.cmake:[0-9]+ \(find_package\) diff --git a/Tests/RunCMake/MaxRecursionDepth/find_package-invalid-var-stderr.txt b/Tests/RunCMake/MaxRecursionDepth/find_package-invalid-var-stderr.txt index 5d31e29..0119953 100644 --- a/Tests/RunCMake/MaxRecursionDepth/find_package-invalid-var-stderr.txt +++ b/Tests/RunCMake/MaxRecursionDepth/find_package-invalid-var-stderr.txt @@ -1,5 +1,5 @@ [0-9]+ -CMake Error at FindRecursivePackage\.cmake:1 \(message\): - Maximum recursion depth of [0-9]+ exceeded +CMake Error at FindRecursivePackage.cmake:[0-9]+ \(find_package\): + find_package maximum nesting depth of [0-9]+ exceeded. Call Stack \(most recent call first\): - FindRecursivePackage\.cmake:3 \(find_package\) + FindRecursivePackage.cmake:[0-9]+ \(find_package\) diff --git a/Tests/RunCMake/MaxRecursionDepth/function-env-result.txt b/Tests/RunCMake/MaxRecursionDepth/function-env-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/MaxRecursionDepth/function-env-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/MaxRecursionDepth/function-env-script-result.txt b/Tests/RunCMake/MaxRecursionDepth/function-env-script-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/MaxRecursionDepth/function-env-script-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/MaxRecursionDepth/function-env-script-stderr.txt b/Tests/RunCMake/MaxRecursionDepth/function-env-script-stderr.txt new file mode 100644 index 0000000..61304b1 --- /dev/null +++ b/Tests/RunCMake/MaxRecursionDepth/function-env-script-stderr.txt @@ -0,0 +1,21 @@ +^3 +4 +5 +6 +7 +8 +9 +10 +CMake Error at .*/function\.cmake:2 \(message\): + Maximum recursion depth of 10 exceeded +Call Stack \(most recent call first\): + .*/function\.cmake:4 \(recursive\) + .*/function\.cmake:4 \(recursive\) + .*/function\.cmake:4 \(recursive\) + .*/function\.cmake:4 \(recursive\) + .*/function\.cmake:4 \(recursive\) + .*/function\.cmake:4 \(recursive\) + .*/function\.cmake:4 \(recursive\) + .*/function\.cmake:4 \(recursive\) + .*/function\.cmake:7 \(recursive\) + .*/CMakeLists\.txt:5 \(include\)$ diff --git a/Tests/RunCMake/MaxRecursionDepth/function-env-stderr.txt b/Tests/RunCMake/MaxRecursionDepth/function-env-stderr.txt new file mode 100644 index 0000000..54e72af --- /dev/null +++ b/Tests/RunCMake/MaxRecursionDepth/function-env-stderr.txt @@ -0,0 +1,21 @@ +^3 +4 +5 +6 +7 +8 +9 +10 +CMake Error at function\.cmake:2 \(message\): + Maximum recursion depth of 10 exceeded +Call Stack \(most recent call first\): + function\.cmake:4 \(recursive\) + function\.cmake:4 \(recursive\) + function\.cmake:4 \(recursive\) + function\.cmake:4 \(recursive\) + function\.cmake:4 \(recursive\) + function\.cmake:4 \(recursive\) + function\.cmake:4 \(recursive\) + function\.cmake:4 \(recursive\) + function\.cmake:7 \(recursive\) + CMakeLists\.txt:5 \(include\)$ diff --git a/Tests/RunCMake/MaxRecursionDepth/function-invalid-env-result.txt b/Tests/RunCMake/MaxRecursionDepth/function-invalid-env-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/MaxRecursionDepth/function-invalid-env-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/MaxRecursionDepth/function-invalid-env-script-result.txt b/Tests/RunCMake/MaxRecursionDepth/function-invalid-env-script-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/MaxRecursionDepth/function-invalid-env-script-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/MaxRecursionDepth/function-invalid-env-script-stderr.txt b/Tests/RunCMake/MaxRecursionDepth/function-invalid-env-script-stderr.txt new file mode 100644 index 0000000..92de1fb --- /dev/null +++ b/Tests/RunCMake/MaxRecursionDepth/function-invalid-env-script-stderr.txt @@ -0,0 +1,5 @@ +[0-9]+ +CMake Error at .*/function\.cmake:2 \(message\): + Maximum recursion depth of [0-9]+ exceeded +Call Stack \(most recent call first\): + .*/function\.cmake:4 \(recursive\) diff --git a/Tests/RunCMake/MaxRecursionDepth/function-invalid-env-stderr.txt b/Tests/RunCMake/MaxRecursionDepth/function-invalid-env-stderr.txt new file mode 100644 index 0000000..5c25c4b --- /dev/null +++ b/Tests/RunCMake/MaxRecursionDepth/function-invalid-env-stderr.txt @@ -0,0 +1,5 @@ +[0-9]+ +CMake Error at function\.cmake:2 \(message\): + Maximum recursion depth of [0-9]+ exceeded +Call Stack \(most recent call first\): + function\.cmake:4 \(recursive\) diff --git a/Tests/RunCMake/MaxRecursionDepth/include-env-result.txt b/Tests/RunCMake/MaxRecursionDepth/include-env-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/MaxRecursionDepth/include-env-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/MaxRecursionDepth/include-env-script-result.txt b/Tests/RunCMake/MaxRecursionDepth/include-env-script-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/MaxRecursionDepth/include-env-script-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/MaxRecursionDepth/include-env-script-stderr.txt b/Tests/RunCMake/MaxRecursionDepth/include-env-script-stderr.txt new file mode 100644 index 0000000..f55f505 --- /dev/null +++ b/Tests/RunCMake/MaxRecursionDepth/include-env-script-stderr.txt @@ -0,0 +1,21 @@ +^3 +4 +5 +6 +7 +8 +9 +10 +CMake Error at .*/include_recursive\.cmake:1 \(message\): + Maximum recursion depth of 10 exceeded +Call Stack \(most recent call first\): + .*/include_recursive\.cmake:3 \(include\) + .*/include_recursive\.cmake:3 \(include\) + .*/include_recursive\.cmake:3 \(include\) + .*/include_recursive\.cmake:3 \(include\) + .*/include_recursive\.cmake:3 \(include\) + .*/include_recursive\.cmake:3 \(include\) + .*/include_recursive\.cmake:3 \(include\) + .*/include_recursive\.cmake:3 \(include\) + .*/include\.cmake:2 \(include\) + .*/CMakeLists\.txt:5 \(include\)$ diff --git a/Tests/RunCMake/MaxRecursionDepth/include-env-stderr.txt b/Tests/RunCMake/MaxRecursionDepth/include-env-stderr.txt new file mode 100644 index 0000000..ff33985 --- /dev/null +++ b/Tests/RunCMake/MaxRecursionDepth/include-env-stderr.txt @@ -0,0 +1,21 @@ +^3 +4 +5 +6 +7 +8 +9 +10 +CMake Error at include_recursive\.cmake:1 \(message\): + Maximum recursion depth of 10 exceeded +Call Stack \(most recent call first\): + include_recursive\.cmake:3 \(include\) + include_recursive\.cmake:3 \(include\) + include_recursive\.cmake:3 \(include\) + include_recursive\.cmake:3 \(include\) + include_recursive\.cmake:3 \(include\) + include_recursive\.cmake:3 \(include\) + include_recursive\.cmake:3 \(include\) + include_recursive\.cmake:3 \(include\) + include\.cmake:2 \(include\) + CMakeLists\.txt:5 \(include\)$ diff --git a/Tests/RunCMake/MaxRecursionDepth/include-invalid-env-result.txt b/Tests/RunCMake/MaxRecursionDepth/include-invalid-env-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/MaxRecursionDepth/include-invalid-env-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/MaxRecursionDepth/include-invalid-env-script-result.txt b/Tests/RunCMake/MaxRecursionDepth/include-invalid-env-script-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/MaxRecursionDepth/include-invalid-env-script-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/MaxRecursionDepth/include-invalid-env-script-stderr.txt b/Tests/RunCMake/MaxRecursionDepth/include-invalid-env-script-stderr.txt new file mode 100644 index 0000000..0510e7c --- /dev/null +++ b/Tests/RunCMake/MaxRecursionDepth/include-invalid-env-script-stderr.txt @@ -0,0 +1,5 @@ +[0-9]+ +CMake Error at .*/include_recursive\.cmake:1 \(message\): + Maximum recursion depth of [0-9]+ exceeded +Call Stack \(most recent call first\): + .*/include_recursive\.cmake:3 \(include\) diff --git a/Tests/RunCMake/MaxRecursionDepth/include-invalid-env-stderr.txt b/Tests/RunCMake/MaxRecursionDepth/include-invalid-env-stderr.txt new file mode 100644 index 0000000..b1494a8 --- /dev/null +++ b/Tests/RunCMake/MaxRecursionDepth/include-invalid-env-stderr.txt @@ -0,0 +1,5 @@ +[0-9]+ +CMake Error at include_recursive\.cmake:1 \(message\): + Maximum recursion depth of [0-9]+ exceeded +Call Stack \(most recent call first\): + include_recursive\.cmake:3 \(include\) diff --git a/Tests/RunCMake/MaxRecursionDepth/macro-env-result.txt b/Tests/RunCMake/MaxRecursionDepth/macro-env-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/MaxRecursionDepth/macro-env-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/MaxRecursionDepth/macro-env-script-result.txt b/Tests/RunCMake/MaxRecursionDepth/macro-env-script-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/MaxRecursionDepth/macro-env-script-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/MaxRecursionDepth/macro-env-script-stderr.txt b/Tests/RunCMake/MaxRecursionDepth/macro-env-script-stderr.txt new file mode 100644 index 0000000..142e068 --- /dev/null +++ b/Tests/RunCMake/MaxRecursionDepth/macro-env-script-stderr.txt @@ -0,0 +1,21 @@ +^3 +4 +5 +6 +7 +8 +9 +10 +CMake Error at .*/macro\.cmake:2 \(message\): + Maximum recursion depth of 10 exceeded +Call Stack \(most recent call first\): + .*/macro\.cmake:4 \(recursive\) + .*/macro\.cmake:4 \(recursive\) + .*/macro\.cmake:4 \(recursive\) + .*/macro\.cmake:4 \(recursive\) + .*/macro\.cmake:4 \(recursive\) + .*/macro\.cmake:4 \(recursive\) + .*/macro\.cmake:4 \(recursive\) + .*/macro\.cmake:4 \(recursive\) + .*/macro\.cmake:7 \(recursive\) + .*/CMakeLists\.txt:5 \(include\)$ diff --git a/Tests/RunCMake/MaxRecursionDepth/macro-env-stderr.txt b/Tests/RunCMake/MaxRecursionDepth/macro-env-stderr.txt new file mode 100644 index 0000000..71de553 --- /dev/null +++ b/Tests/RunCMake/MaxRecursionDepth/macro-env-stderr.txt @@ -0,0 +1,21 @@ +^3 +4 +5 +6 +7 +8 +9 +10 +CMake Error at macro\.cmake:2 \(message\): + Maximum recursion depth of 10 exceeded +Call Stack \(most recent call first\): + macro\.cmake:4 \(recursive\) + macro\.cmake:4 \(recursive\) + macro\.cmake:4 \(recursive\) + macro\.cmake:4 \(recursive\) + macro\.cmake:4 \(recursive\) + macro\.cmake:4 \(recursive\) + macro\.cmake:4 \(recursive\) + macro\.cmake:4 \(recursive\) + macro\.cmake:7 \(recursive\) + CMakeLists\.txt:5 \(include\)$ diff --git a/Tests/RunCMake/MaxRecursionDepth/macro-invalid-env-result.txt b/Tests/RunCMake/MaxRecursionDepth/macro-invalid-env-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/MaxRecursionDepth/macro-invalid-env-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/MaxRecursionDepth/macro-invalid-env-script-result.txt b/Tests/RunCMake/MaxRecursionDepth/macro-invalid-env-script-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/MaxRecursionDepth/macro-invalid-env-script-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/MaxRecursionDepth/macro-invalid-env-script-stderr.txt b/Tests/RunCMake/MaxRecursionDepth/macro-invalid-env-script-stderr.txt new file mode 100644 index 0000000..c67be57 --- /dev/null +++ b/Tests/RunCMake/MaxRecursionDepth/macro-invalid-env-script-stderr.txt @@ -0,0 +1,5 @@ +[0-9]+ +CMake Error at .*/macro\.cmake:2 \(message\): + Maximum recursion depth of [0-9]+ exceeded +Call Stack \(most recent call first\): + .*/macro\.cmake:4 \(recursive\) diff --git a/Tests/RunCMake/MaxRecursionDepth/macro-invalid-env-stderr.txt b/Tests/RunCMake/MaxRecursionDepth/macro-invalid-env-stderr.txt new file mode 100644 index 0000000..0b27162 --- /dev/null +++ b/Tests/RunCMake/MaxRecursionDepth/macro-invalid-env-stderr.txt @@ -0,0 +1,5 @@ +[0-9]+ +CMake Error at macro\.cmake:2 \(message\): + Maximum recursion depth of [0-9]+ exceeded +Call Stack \(most recent call first\): + macro\.cmake:4 \(recursive\) diff --git a/Tests/RunCMake/MaxRecursionDepth/variable_watch-env-result.txt b/Tests/RunCMake/MaxRecursionDepth/variable_watch-env-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/MaxRecursionDepth/variable_watch-env-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/MaxRecursionDepth/variable_watch-env-script-result.txt b/Tests/RunCMake/MaxRecursionDepth/variable_watch-env-script-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/MaxRecursionDepth/variable_watch-env-script-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/MaxRecursionDepth/variable_watch-env-script-stderr.txt b/Tests/RunCMake/MaxRecursionDepth/variable_watch-env-script-stderr.txt new file mode 100644 index 0000000..52fedd3 --- /dev/null +++ b/Tests/RunCMake/MaxRecursionDepth/variable_watch-env-script-stderr.txt @@ -0,0 +1,22 @@ +^4 +6 +8 +10 +CMake Error at .*/variable_watch\.cmake:[0-9]+ \(update_x\): + Maximum recursion depth of 10 exceeded +Call Stack \(most recent call first\): + .*/variable_watch\.cmake:5 \(set\) + .*/variable_watch\.cmake:[0-9]+ \(update_x\) + .*/variable_watch\.cmake:5 \(set\) + .*/variable_watch\.cmake:[0-9]+ \(update_x\) + .*/variable_watch\.cmake:5 \(set\) + .*/variable_watch\.cmake:[0-9]+ \(update_x\) + .*/variable_watch\.cmake:5 \(set\) + .*/variable_watch\.cmake:[0-9]+ \(update_x\) + .*/variable_watch\.cmake:9 \(set\) + .*/CMakeLists\.txt:5 \(include\) + + +CMake Error: Error in cmake code at +Unknown:0: +A command failed during the invocation of callback "update_x"\.$ diff --git a/Tests/RunCMake/MaxRecursionDepth/variable_watch-env-stderr.txt b/Tests/RunCMake/MaxRecursionDepth/variable_watch-env-stderr.txt new file mode 100644 index 0000000..1427f1d --- /dev/null +++ b/Tests/RunCMake/MaxRecursionDepth/variable_watch-env-stderr.txt @@ -0,0 +1,22 @@ +^4 +6 +8 +10 +CMake Error at variable_watch\.cmake:[0-9]+ \(update_x\): + Maximum recursion depth of 10 exceeded +Call Stack \(most recent call first\): + variable_watch\.cmake:5 \(set\) + variable_watch\.cmake:[0-9]+ \(update_x\) + variable_watch\.cmake:5 \(set\) + variable_watch\.cmake:[0-9]+ \(update_x\) + variable_watch\.cmake:5 \(set\) + variable_watch\.cmake:[0-9]+ \(update_x\) + variable_watch\.cmake:5 \(set\) + variable_watch\.cmake:[0-9]+ \(update_x\) + variable_watch\.cmake:9 \(set\) + CMakeLists\.txt:5 \(include\) + + +CMake Error: Error in cmake code at +Unknown:0: +A command failed during the invocation of callback "update_x"\.$ diff --git a/Tests/RunCMake/MaxRecursionDepth/variable_watch-invalid-env-result.txt b/Tests/RunCMake/MaxRecursionDepth/variable_watch-invalid-env-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/MaxRecursionDepth/variable_watch-invalid-env-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/MaxRecursionDepth/variable_watch-invalid-env-script-result.txt b/Tests/RunCMake/MaxRecursionDepth/variable_watch-invalid-env-script-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/MaxRecursionDepth/variable_watch-invalid-env-script-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/MaxRecursionDepth/variable_watch-invalid-env-script-stderr.txt b/Tests/RunCMake/MaxRecursionDepth/variable_watch-invalid-env-script-stderr.txt new file mode 100644 index 0000000..07deee2 --- /dev/null +++ b/Tests/RunCMake/MaxRecursionDepth/variable_watch-invalid-env-script-stderr.txt @@ -0,0 +1,6 @@ +[0-9]+ +CMake Error at .*/variable_watch\.cmake:[0-9]+ \(update_x\): + Maximum recursion depth of [0-9]+ exceeded +Call Stack \(most recent call first\): + .*/variable_watch\.cmake:5 \(set\) + .*/variable_watch\.cmake:[0-9]+ \(update_x\) diff --git a/Tests/RunCMake/MaxRecursionDepth/variable_watch-invalid-env-stderr.txt b/Tests/RunCMake/MaxRecursionDepth/variable_watch-invalid-env-stderr.txt new file mode 100644 index 0000000..b2395b3 --- /dev/null +++ b/Tests/RunCMake/MaxRecursionDepth/variable_watch-invalid-env-stderr.txt @@ -0,0 +1,6 @@ +[0-9]+ +CMake Error at variable_watch\.cmake:[0-9]+ \(update_x\): + Maximum recursion depth of [0-9]+ exceeded +Call Stack \(most recent call first\): + variable_watch\.cmake:5 \(set\) + variable_watch\.cmake:[0-9]+ \(update_x\) diff --git a/Tests/RunCMake/MultiLint/CXX.cmake b/Tests/RunCMake/MultiLint/CXX.cmake index dc30146..3e99e73 100644 --- a/Tests/RunCMake/MultiLint/CXX.cmake +++ b/Tests/RunCMake/MultiLint/CXX.cmake @@ -1,6 +1,6 @@ enable_language(CXX) -set(CMAKE_CXX_INCLUDE_WHAT_YOU_USE "${PSEUDO_IWYU}" -some -args) -set(CMAKE_CXX_CLANG_TIDY "${PSEUDO_TIDY}" -some -args) -set(CMAKE_CXX_CPPLINT "${PSEUDO_CPPLINT}" --verbose=0 --linelength=80) -set(CMAKE_CXX_CPPCHECK "${PSEUDO_CPPCHECK}") +set(CMAKE_CXX_INCLUDE_WHAT_YOU_USE "$<1:${PSEUDO_IWYU}>" -some -args) +set(CMAKE_CXX_CLANG_TIDY "$<1:${PSEUDO_TIDY}>" -some -args) +set(CMAKE_CXX_CPPLINT "$<1:${PSEUDO_CPPLINT}>" --verbose=0 --linelength=80) +set(CMAKE_CXX_CPPCHECK "$<1:${PSEUDO_CPPCHECK}>") add_executable(main main.cxx) diff --git a/Tests/RunCMake/Ninja/RunCMakeTest.cmake b/Tests/RunCMake/Ninja/RunCMakeTest.cmake index 91c48c6..619e94a 100644 --- a/Tests/RunCMake/Ninja/RunCMakeTest.cmake +++ b/Tests/RunCMake/Ninja/RunCMakeTest.cmake @@ -46,6 +46,7 @@ if(WIN32) if(RunCMake_MAKE_PROGRAM) set(maybe_MAKE_PROGRAM "-DRunCMake_MAKE_PROGRAM=${RunCMake_MAKE_PROGRAM}") endif() + run_cmake_script(ShowIncludes-437-ClangCl -DshowIncludes=${showIncludes} ${maybe_MAKE_PROGRAM}) run_cmake_script(ShowIncludes-437-English -DshowIncludes=${showIncludes} ${maybe_MAKE_PROGRAM}) run_cmake_script(ShowIncludes-437-French -DshowIncludes=${showIncludes} ${maybe_MAKE_PROGRAM}) run_cmake_script(ShowIncludes-437-German -DshowIncludes=${showIncludes} ${maybe_MAKE_PROGRAM}) diff --git a/Tests/RunCMake/Ninja/ShowIncludes-437-ClangCl-check.cmake b/Tests/RunCMake/Ninja/ShowIncludes-437-ClangCl-check.cmake new file mode 100644 index 0000000..6136463 --- /dev/null +++ b/Tests/RunCMake/Ninja/ShowIncludes-437-ClangCl-check.cmake @@ -0,0 +1,3 @@ +# 'clang-cl /showIncludes' prefix. +set(expect "Note: including file: ") +include(${CMAKE_CURRENT_LIST_DIR}/ShowIncludes-check.cmake) diff --git a/Tests/RunCMake/Ninja/ShowIncludes-437-ClangCl-stdout.txt b/Tests/RunCMake/Ninja/ShowIncludes-437-ClangCl-stdout.txt new file mode 100644 index 0000000..bda7eab --- /dev/null +++ b/Tests/RunCMake/Ninja/ShowIncludes-437-ClangCl-stdout.txt @@ -0,0 +1 @@ +-- showIncludes='Note: including file: ' diff --git a/Tests/RunCMake/Ninja/ShowIncludes-437-ClangCl.cmake b/Tests/RunCMake/Ninja/ShowIncludes-437-ClangCl.cmake new file mode 100644 index 0000000..7eca3d3 --- /dev/null +++ b/Tests/RunCMake/Ninja/ShowIncludes-437-ClangCl.cmake @@ -0,0 +1,3 @@ +set(CODEPAGE 437) +set(VSLANG "clang-cl") # Special case for test, not a real VS value. +include(${CMAKE_CURRENT_LIST_DIR}/ShowIncludes.cmake) diff --git a/Tests/RunCMake/ObjectLibrary/MissingSource-stderr.txt b/Tests/RunCMake/ObjectLibrary/MissingSource-stderr.txt index 5c7882d..05eb42d 100644 --- a/Tests/RunCMake/ObjectLibrary/MissingSource-stderr.txt +++ b/Tests/RunCMake/ObjectLibrary/MissingSource-stderr.txt @@ -3,7 +3,7 @@ CMake Error at MissingSource.cmake:1 \(add_library\): missing.c - Tried extensions \.c \.C .* -.* -Call Stack \(most recent call first\): + Tried extensions ([^ +]+ +)+Call Stack \(most recent call first\): CMakeLists.txt:3 \(include\) diff --git a/Tests/RunCMake/README.rst b/Tests/RunCMake/README.rst index ebe40cf..d8cae8b 100644 --- a/Tests/RunCMake/README.rst +++ b/Tests/RunCMake/README.rst @@ -82,3 +82,10 @@ match the regular expression are not run. For example:: This will only run subtests in ``RunCMake.Example`` that start with ``example``. + +To speed up the process of creating a new ``RunCMake`` test, you can run a +script that will automatically perform steps 1 through 4 for you:: + + cmake -DRunCMake_TEST_SUITE=<test suite name> -P Tests/RunCMake/AddRunCMakeTestSuite.cmake + +Be sure to run this from the top-level CMake source directory. diff --git a/Tests/RunCMake/ToolchainFile/RunCMakeTest.cmake b/Tests/RunCMake/ToolchainFile/RunCMakeTest.cmake index 7744ee8..b588ce0 100644 --- a/Tests/RunCMake/ToolchainFile/RunCMakeTest.cmake +++ b/Tests/RunCMake/ToolchainFile/RunCMakeTest.cmake @@ -14,6 +14,7 @@ run_cmake_toolchain(LinkFlagsInit) run_cmake_toolchain(CMP0126-NEW) run_cmake_toolchain(CMP0126-OLD) run_cmake_toolchain(CMP0126-WARN) +run_cmake_toolchain(SetCrossCompiling) function(run_IncludeDirectories) run_cmake_toolchain(IncludeDirectories) diff --git a/Tests/RunCMake/ToolchainFile/SetCrossCompiling-stderr.txt b/Tests/RunCMake/ToolchainFile/SetCrossCompiling-stderr.txt new file mode 100644 index 0000000..6642cf6 --- /dev/null +++ b/Tests/RunCMake/ToolchainFile/SetCrossCompiling-stderr.txt @@ -0,0 +1,8 @@ +^CMake Warning \(dev\) at [^ +]*/Modules/CMakeDetermineSystem.cmake:[0-9]+ \(message\): + CMAKE_CROSSCOMPILING has been set by the project, toolchain file, or user\. + CMake is resetting it to false because CMAKE_SYSTEM_NAME was not set\. To + indicate cross compilation, only CMAKE_SYSTEM_NAME needs to be set\. +Call Stack \(most recent call first\): + CMakeLists\.txt:[0-9]+ \(project\) +This warning is for project developers\. Use -Wno-dev to suppress it\.$ diff --git a/Tests/RunCMake/ToolchainFile/SetCrossCompiling-toolchain.cmake b/Tests/RunCMake/ToolchainFile/SetCrossCompiling-toolchain.cmake new file mode 100644 index 0000000..170e26c --- /dev/null +++ b/Tests/RunCMake/ToolchainFile/SetCrossCompiling-toolchain.cmake @@ -0,0 +1 @@ +set(CMAKE_CROSSCOMPILING TRUE) diff --git a/Tests/RunCMake/ToolchainFile/SetCrossCompiling.cmake b/Tests/RunCMake/ToolchainFile/SetCrossCompiling.cmake new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/Tests/RunCMake/ToolchainFile/SetCrossCompiling.cmake diff --git a/Tests/RunCMake/VS10Project/CustomCommandParallel-check.cmake b/Tests/RunCMake/VS10Project/CustomCommandParallel-check.cmake new file mode 100644 index 0000000..4c8ad00 --- /dev/null +++ b/Tests/RunCMake/VS10Project/CustomCommandParallel-check.cmake @@ -0,0 +1,52 @@ +set(vcProjectFile "${RunCMake_TEST_BINARY_DIR}/foo.vcxproj") +if(NOT EXISTS "${vcProjectFile}") + set(RunCMake_TEST_FAILED "Project file ${vcProjectFile} does not exist.") + return() +endif() + +set(found_CustomBuild_cmp0147_new 0) +set(found_CustomBuild_cmp0147_old 0) +set(found_CustomBuild_CMakeLists 0) +set(found_BuildInParallel_cmp0147_new 0) +set(found_BuildInParallel_cmp0147_old 0) +set(found_BuildInParallel_CMakeLists 0) +set(in_CustomBuild "") +file(STRINGS "${vcProjectFile}" lines) +foreach(line IN LISTS lines) + if(line MATCHES [[<CustomBuild Include=".*\\cmp0147-old\.txt\.rule">]]) + set(found_CustomBuild_cmp0147_old 1) + set(in_CustomBuild "cmp0147_old") + endif() + if(line MATCHES [[<CustomBuild Include=".*\\cmp0147-new\.txt\.rule">]]) + set(found_CustomBuild_cmp0147_new 1) + set(in_CustomBuild "cmp0147_new") + endif() + if(line MATCHES [[<CustomBuild Include=".*\\CMakeLists\.txt">]]) + set(found_CustomBuild_CMakeLists 1) + set(in_CustomBuild "CMakeLists") + endif() + if(line MATCHES [[</CustomBuild>]]) + set(in_CustomBuild "") + endif() + if(line MATCHES [[<BuildInParallel .*>true</BuildInParallel>]] AND in_CustomBuild) + set(found_BuildInParallel_${in_CustomBuild} 1) + endif() +endforeach() +if(NOT found_CustomBuild_cmp0147_new) + string(APPEND RunCMake_TEST_FAILED "CustomBuild for cmp0147-new.txt.rule not found in\n ${vcProjectFile}\n") +endif() +if(NOT found_CustomBuild_cmp0147_old) + string(APPEND RunCMake_TEST_FAILED "CustomBuild for cmp0147-old.txt.rule not found in\n ${vcProjectFile}\n") +endif() +if(NOT found_CustomBuild_CMakeLists) + string(APPEND RunCMake_TEST_FAILED "CustomBuild for CMakeLists.txt not found in\n ${vcProjectFile}\n") +endif() +if(NOT found_BuildInParallel_cmp0147_new) + string(APPEND RunCMake_TEST_FAILED "BuildInParallel for cmp0147-new.txt.rule not found in\n ${vcProjectFile}\n") +endif() +if(found_BuildInParallel_cmp0147_old) + string(APPEND RunCMake_TEST_FAILED "BuildInParallel for cmp0147-old.txt.rule incorrectly found in\n ${vcProjectFile}\n") +endif() +if(found_BuildInParallel_CMakeLists) + string(APPEND RunCMake_TEST_FAILED "BuildInParallel for CMakeLists.txt incorrectly found in\n ${vcProjectFile}\n") +endif() diff --git a/Tests/RunCMake/VS10Project/CustomCommandParallel.cmake b/Tests/RunCMake/VS10Project/CustomCommandParallel.cmake new file mode 100644 index 0000000..784fc68 --- /dev/null +++ b/Tests/RunCMake/VS10Project/CustomCommandParallel.cmake @@ -0,0 +1,5 @@ +cmake_policy(VERSION 3.26) # CMP0147 left unset +add_custom_command(OUTPUT "cmp0147-old.txt" COMMAND echo) +cmake_policy(SET CMP0147 NEW) +add_custom_command(OUTPUT "cmp0147-new.txt" COMMAND echo) +add_custom_target(foo DEPENDS "cmp0147-old.txt" "cmp0147-new.txt") diff --git a/Tests/RunCMake/VS10Project/RunCMakeTest.cmake b/Tests/RunCMake/VS10Project/RunCMakeTest.cmake index ed74896..669049a 100644 --- a/Tests/RunCMake/VS10Project/RunCMakeTest.cmake +++ b/Tests/RunCMake/VS10Project/RunCMakeTest.cmake @@ -8,6 +8,9 @@ if(CMAKE_C_COMPILER_ID STREQUAL "MSVC" AND CMAKE_C_COMPILER_VERSION VERSION_GREA endif() run_cmake(CustomCommandGenex) +if(NOT RunCMake_GENERATOR MATCHES "^Visual Studio 1[1-5] ") + run_cmake(CustomCommandParallel) +endif() run_cmake(VsCsharpSourceGroup) run_cmake(VsCSharpCompilerOpts) run_cmake(ExplicitCMakeLists) diff --git a/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/RunCMakeTest.cmake b/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/RunCMakeTest.cmake index 43b406b..a68607e 100644 --- a/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/RunCMakeTest.cmake +++ b/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/RunCMakeTest.cmake @@ -9,6 +9,10 @@ function(run_install_test case) run_cmake_command(${case}-build ${CMAKE_COMMAND} --build . --config Debug) # Check "all" components. set(CMAKE_INSTALL_PREFIX ${RunCMake_TEST_BINARY_DIR}/root-all) + set(maybe_stderr "${case}-all-stderr-${CMAKE_C_COMPILER_ID}.txt") + if(EXISTS "${RunCMake_SOURCE_DIR}/${maybe_stderr}") + set(RunCMake-stderr-file "${maybe_stderr}") + endif() run_cmake_command(${case}-all ${CMAKE_COMMAND} --install . --prefix ${CMAKE_INSTALL_PREFIX} --config Debug) endfunction() diff --git a/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/windows-all-check.cmake b/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/windows-all-check.cmake index cb0e534..10b7b82 100644 --- a/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/windows-all-check.cmake +++ b/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/windows-all-check.cmake @@ -1,19 +1,29 @@ +if(CMAKE_C_COMPILER_ID STREQUAL "Borland") + # Borland upper-cases dll names referenced in import libraries. + set(conflict_dll [[CONFLICT\.DLL]]) + set(unresolved_dll [[UNRESOLVED\.DLL]]) +else() + set(conflict_dll [[conflict\.dll]]) + set(unresolved_dll [[unresolved\.dll]]) +endif() + set(_check [=[[^;]*/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/windows-build/root-all/bin/\.conflict/\.\./(lib)?libdir\.dll]=] [=[[^;]*/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/windows-build/root-all/bin/\.search/(lib)?search\.dll]=] + [=[[^;]*/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/windows-build/root-all/bin/(lib)?MixedCase\.dll]=] [=[[^;]*/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/windows-build/root-all/bin/(lib)?testlib\.dll]=] ) check_contents(deps/deps1.txt "^${_check}$") check_contents(deps/deps2.txt "^${_check}$") check_contents(deps/deps3.txt "^${_check}$") set(_check - [=[(lib)?unresolved\.dll]=] + "(lib)?${unresolved_dll}" ) check_contents(deps/udeps1.txt "^${_check}$") check_contents(deps/udeps2.txt "^${_check}$") check_contents(deps/udeps3.txt "^${_check}$") set(_check - "^(lib)?conflict\\.dll:[^;]*/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/windows-build/root-all/bin/\\.conflict/(lib)?conflict\\.dll;[^;]*/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/windows-build/root-all/bin/(lib)?conflict\\.dll\n$" + "^(lib)?${conflict_dll}:[^;]*/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/windows-build/root-all/bin/\\.conflict/(lib)?conflict\\.dll;[^;]*/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/windows-build/root-all/bin/(lib)?conflict\\.dll\n$" ) check_contents(deps/cdeps1.txt "${_check}") check_contents(deps/cdeps2.txt "${_check}") diff --git a/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/windows-conflict-all-stderr-Borland.txt b/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/windows-conflict-all-stderr-Borland.txt new file mode 100644 index 0000000..607e4b8 --- /dev/null +++ b/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/windows-conflict-all-stderr-Borland.txt @@ -0,0 +1,7 @@ +^CMake Error at cmake_install\.cmake:[0-9]+ \(file\): + file Multiple conflicting paths found for PATH\.DLL: + + [^ +]*/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/windows-conflict-build/root-all/lib/test1/path\.dll + [^ +]*/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/windows-conflict-build/root-all/lib/test2/path\.dll$ diff --git a/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/windows-unresolved-all-stderr-Borland.txt b/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/windows-unresolved-all-stderr-Borland.txt new file mode 100644 index 0000000..fea1083 --- /dev/null +++ b/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/windows-unresolved-all-stderr-Borland.txt @@ -0,0 +1,4 @@ +^CMake Error at cmake_install\.cmake:[0-9]+ \(file\): + file Could not resolve runtime dependencies: + + UNRESOLVED\.DLL$ diff --git a/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/windows.cmake b/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/windows.cmake index 9160ce5..aad9077 100644 --- a/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/windows.cmake +++ b/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/windows.cmake @@ -8,6 +8,7 @@ set(testlib_names search unresolved conflict + MixedCase ) file(REMOVE "${CMAKE_BINARY_DIR}/testlib.c") @@ -34,7 +35,7 @@ file(WRITE "${CMAKE_BINARY_DIR}/testlib_noconflict.c" "__declspec(dllimport) ext add_library(testlib_noconflict SHARED "${CMAKE_BINARY_DIR}/testlib_noconflict.c") target_link_libraries(testlib_noconflict PRIVATE libdir) -install(TARGETS testlib libdir_postexcluded libdir conflict testlib_noconflict DESTINATION bin) +install(TARGETS testlib libdir_postexcluded libdir conflict MixedCase testlib_noconflict DESTINATION bin) install(TARGETS libdir search_postexcluded search DESTINATION bin/.search) # Prefixing with "." ensures it is the first item after list(SORT) install(TARGETS testlib_conflict conflict DESTINATION bin/.conflict) @@ -61,6 +62,7 @@ install(CODE [[ "^(lib)?search\\.dll$" "^(lib)?unresolved\\.dll$" "^(lib)?conflict\\.dll$" + "^(lib)?mixedcase\\.dll$" "^kernel32\\.dll$" PRE_EXCLUDE_REGEXES ".*" POST_INCLUDE_REGEXES @@ -68,6 +70,7 @@ install(CODE [[ "^.*/(lib)?libdir\\.dll$" "^.*/(lib)?search\\.dll$" "^.*/(lib)?conflict\\.dll$" + "^.*/(lib)?mixedcase\\.dll$" POST_EXCLUDE_REGEXES ".*" DIRECTORIES "${CMAKE_INSTALL_PREFIX}/bin/.search" diff --git a/Tests/RunCMake/file/REAL_PATH.cmake b/Tests/RunCMake/file/REAL_PATH.cmake index 0b5d3c0..9c5d4ea 100644 --- a/Tests/RunCMake/file/REAL_PATH.cmake +++ b/Tests/RunCMake/file/REAL_PATH.cmake @@ -34,3 +34,19 @@ file(REAL_PATH "~/test.txt" real_path EXPAND_TILDE) if (NOT real_path STREQUAL "${HOME_DIR}/test.txt") message(SEND_ERROR "real path is \"${real_path}\", should be \"${HOME_DIR}/test.txt\"") endif() + +if (WIN32) + cmake_policy(SET CMP0139 NEW) + + set(in "${CMAKE_CURRENT_BINARY_DIR}/AbC.TxT") + + file(REMOVE "${in}") + file(TOUCH "${in}") + + string(TOLOWER "${in}" low) + file(REAL_PATH "${low}" out) + + if(NOT "${out}" PATH_EQUAL "${in}") + message(SEND_ERROR "real path is \"${out}\", should be \"${in}\"") + endif() +endif() diff --git a/Tests/RunCMake/find_package/CMP0146-NEW-stderr.txt b/Tests/RunCMake/find_package/CMP0146-NEW-stderr.txt new file mode 100644 index 0000000..0162852 --- /dev/null +++ b/Tests/RunCMake/find_package/CMP0146-NEW-stderr.txt @@ -0,0 +1,4 @@ +^CMake Warning at CMP0146-NEW\.cmake:[0-9]+ \(find_package\): + No "FindCUDA\.cmake" found in CMAKE_MODULE_PATH\. +Call Stack \(most recent call first\): + CMakeLists\.txt:[0-9]+ \(include\) diff --git a/Tests/RunCMake/find_package/CMP0146-NEW.cmake b/Tests/RunCMake/find_package/CMP0146-NEW.cmake new file mode 100644 index 0000000..b373227 --- /dev/null +++ b/Tests/RunCMake/find_package/CMP0146-NEW.cmake @@ -0,0 +1,7 @@ +cmake_policy(SET CMP0146 NEW) +set(_FindCUDA_testing TRUE) +find_package(CUDA MODULE) + +if(_FindCUDA_included) + message(FATAL_ERROR "FindCUDA.cmake erroneously included") +endif() diff --git a/Tests/RunCMake/find_package/CMP0146-OLD.cmake b/Tests/RunCMake/find_package/CMP0146-OLD.cmake new file mode 100644 index 0000000..77cd1f5 --- /dev/null +++ b/Tests/RunCMake/find_package/CMP0146-OLD.cmake @@ -0,0 +1,7 @@ +cmake_policy(SET CMP0146 OLD) +set(_FindCUDA_testing TRUE) +find_package(CUDA MODULE) + +if(NOT _FindCUDA_included) + message(FATAL_ERROR "FindCUDA.cmake not included") +endif() diff --git a/Tests/RunCMake/find_package/CMP0146-WARN-stderr.txt b/Tests/RunCMake/find_package/CMP0146-WARN-stderr.txt new file mode 100644 index 0000000..2cd9c5f --- /dev/null +++ b/Tests/RunCMake/find_package/CMP0146-WARN-stderr.txt @@ -0,0 +1,8 @@ +CMake Warning \(dev\) at CMP0146-WARN\.cmake:[0-9]+ \(find_package\): + Policy CMP0146 is not set: The FindCUDA module is removed\. Run "cmake + --help-policy CMP0146" for policy details\. Use the cmake_policy command to + set the policy and suppress this warning\. + +Call Stack \(most recent call first\): + CMakeLists\.txt:[0-9]+ \(include\) +This warning is for project developers\. Use -Wno-dev to suppress it\.$ diff --git a/Tests/RunCMake/find_package/CMP0146-WARN.cmake b/Tests/RunCMake/find_package/CMP0146-WARN.cmake new file mode 100644 index 0000000..276daf2 --- /dev/null +++ b/Tests/RunCMake/find_package/CMP0146-WARN.cmake @@ -0,0 +1,6 @@ +set(_FindCUDA_testing TRUE) +find_package(CUDA MODULE) + +if(NOT _FindCUDA_included) + message(FATAL_ERROR "FindCUDA.cmake not included") +endif() diff --git a/Tests/RunCMake/find_package/CMP0147-NEW-result.txt b/Tests/RunCMake/find_package/CMP0147-NEW-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/find_package/CMP0147-NEW-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/find_package/CMP0147-NEW-stderr.txt b/Tests/RunCMake/find_package/CMP0147-NEW-stderr.txt new file mode 100644 index 0000000..1caf6c5 --- /dev/null +++ b/Tests/RunCMake/find_package/CMP0147-NEW-stderr.txt @@ -0,0 +1,7 @@ +^CMake Error at [^ +]*/Modules/FindCUDA.cmake:[0-9]+ \(message\): + The FindCUDA module does not work in Visual Studio with policy CMP0147\. +Call Stack \(most recent call first\): + CMP0147-common\.cmake:[0-9]+ \(find_package\) + CMP0147-NEW\.cmake:[0-9]+ \(include\) + CMakeLists\.txt:[0-9]+ \(include\)$ diff --git a/Tests/RunCMake/find_package/CMP0147-NEW.cmake b/Tests/RunCMake/find_package/CMP0147-NEW.cmake new file mode 100644 index 0000000..0ca5b6c --- /dev/null +++ b/Tests/RunCMake/find_package/CMP0147-NEW.cmake @@ -0,0 +1,2 @@ +cmake_policy(SET CMP0147 NEW) +include(CMP0147-common.cmake) diff --git a/Tests/RunCMake/find_package/CMP0147-OLD.cmake b/Tests/RunCMake/find_package/CMP0147-OLD.cmake new file mode 100644 index 0000000..61ecee5 --- /dev/null +++ b/Tests/RunCMake/find_package/CMP0147-OLD.cmake @@ -0,0 +1,2 @@ +cmake_policy(SET CMP0147 OLD) +include(CMP0147-common.cmake) diff --git a/Tests/RunCMake/find_package/CMP0147-WARN.cmake b/Tests/RunCMake/find_package/CMP0147-WARN.cmake new file mode 100644 index 0000000..d5f3e91 --- /dev/null +++ b/Tests/RunCMake/find_package/CMP0147-WARN.cmake @@ -0,0 +1,2 @@ +# leave CMP0147 unset +include(CMP0147-common.cmake) diff --git a/Tests/RunCMake/find_package/CMP0147-common.cmake b/Tests/RunCMake/find_package/CMP0147-common.cmake new file mode 100644 index 0000000..68a86ee --- /dev/null +++ b/Tests/RunCMake/find_package/CMP0147-common.cmake @@ -0,0 +1,3 @@ +cmake_policy(SET CMP0146 OLD) +set(_FindCUDA_testing TRUE) +find_package(CUDA MODULE) diff --git a/Tests/RunCMake/find_package/RunCMakeTest.cmake b/Tests/RunCMake/find_package/RunCMakeTest.cmake index f0bb011..26eb908 100644 --- a/Tests/RunCMake/find_package/RunCMakeTest.cmake +++ b/Tests/RunCMake/find_package/RunCMakeTest.cmake @@ -39,6 +39,14 @@ run_cmake(CMP0084-NEW) run_cmake(CMP0145-OLD) run_cmake(CMP0145-WARN) run_cmake(CMP0145-NEW) +run_cmake(CMP0146-OLD) +run_cmake(CMP0146-WARN) +run_cmake(CMP0146-NEW) +if(RunCMake_GENERATOR MATCHES "Visual Studio") + run_cmake(CMP0147-OLD) + run_cmake(CMP0147-WARN) + run_cmake(CMP0147-NEW) +endif() run_cmake(WrongVersionRange) run_cmake(EmptyVersionRange) run_cmake(VersionRangeWithEXACT) diff --git a/Tests/RunCMake/include/CMP0024-NEW-stderr.txt b/Tests/RunCMake/include/CMP0024-NEW-stderr.txt index 0fdb3ca..26ced80 100644 --- a/Tests/RunCMake/include/CMP0024-NEW-stderr.txt +++ b/Tests/RunCMake/include/CMP0024-NEW-stderr.txt @@ -1,8 +1,9 @@ -CMake Error at subdir2/CMakeLists.txt:2 \(include\): +^CMake Error at subdir2/CMakeLists\.txt:2 \(include\): The file - .*/Tests/RunCMake/include/CMP0024-NEW-build/subdir1/theTargets.cmake + [^ +]*/Tests/RunCMake/include/CMP0024-NEW-build/subdir1/theTargets\.cmake - was generated by the export\(\) command. It may not be used as the argument - to the include\(\) command. Use ALIAS targets instead to refer to targets by - alternative names. + was generated by the export\(\) command\. It may not be used as the argument + to the include\(\) command\. Use ALIAS targets instead to refer to targets by + alternative names\. diff --git a/Tests/RunCMake/include/CMP0024-NEW.cmake b/Tests/RunCMake/include/CMP0024-NEW.cmake index 0e03d2a..783cf78 100644 --- a/Tests/RunCMake/include/CMP0024-NEW.cmake +++ b/Tests/RunCMake/include/CMP0024-NEW.cmake @@ -1,8 +1,6 @@ enable_language(CXX) -cmake_policy(SET CMP0024 NEW) - add_library(foo SHARED empty.cpp) add_subdirectory(subdir1) diff --git a/Tests/RunCMake/include/CMP0024-WARN-stderr.txt b/Tests/RunCMake/include/CMP0024-WARN-stderr.txt index 9c79007..8472f41 100644 --- a/Tests/RunCMake/include/CMP0024-WARN-stderr.txt +++ b/Tests/RunCMake/include/CMP0024-WARN-stderr.txt @@ -1,14 +1,24 @@ -CMake Warning \(dev\) at subdir2/CMakeLists.txt:2 \(include\): +^CMake Deprecation Warning at CMP0024-WARN\.cmake:[0-9]+ \(cmake_policy\): + Compatibility with CMake < 3\.5 will be removed from a future version of + CMake. + + Update the VERSION argument <min> value or use a \.\.\.<max> suffix to tell + CMake that the project does not need compatibility with older versions\. +Call Stack \(most recent call first\): + CMakeLists\.txt:[0-9]+ \(include\) ++ +CMake Warning \(dev\) at subdir2/CMakeLists\.txt:2 \(include\): Policy CMP0024 is not set: Disallow include export result. Run "cmake - --help-policy CMP0024" for policy details. Use the cmake_policy command to - set the policy and suppress this warning. + --help-policy CMP0024" for policy details\. Use the cmake_policy command to + set the policy and suppress this warning\. The file - .*/Tests/RunCMake/include/CMP0024-WARN-build/subdir1/theTargets.cmake + [^ +]*/Tests/RunCMake/include/CMP0024-WARN-build/subdir1/theTargets\.cmake - was generated by the export\(\) command. It should not be used as the - argument to the include\(\) command. Use ALIAS targets instead to refer to - targets by alternative names. + was generated by the export\(\) command\. It should not be used as the + argument to the include\(\) command\. Use ALIAS targets instead to refer to + targets by alternative names\. -This warning is for project developers. Use -Wno-dev to suppress it. +This warning is for project developers\. Use -Wno-dev to suppress it\. diff --git a/Tests/RunCMake/include/CMP0024-WARN.cmake b/Tests/RunCMake/include/CMP0024-WARN.cmake index 783cf78..f267a5a 100644 --- a/Tests/RunCMake/include/CMP0024-WARN.cmake +++ b/Tests/RunCMake/include/CMP0024-WARN.cmake @@ -1,3 +1,4 @@ +cmake_policy(VERSION 2.8.12) # Leave CMP0024 unset. enable_language(CXX) diff --git a/Tests/RunCMake/include/CMP0146-NEW-name-result.txt b/Tests/RunCMake/include/CMP0146-NEW-name-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/include/CMP0146-NEW-name-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/include/CMP0146-NEW-name-stderr.txt b/Tests/RunCMake/include/CMP0146-NEW-name-stderr.txt new file mode 100644 index 0000000..7d9e7d8 --- /dev/null +++ b/Tests/RunCMake/include/CMP0146-NEW-name-stderr.txt @@ -0,0 +1,6 @@ +^CMake Error at CMP0146-NEW-name\.cmake:[0-9]+ \(include\): + include could not find requested file: + + FindCUDA +Call Stack \(most recent call first\): + CMakeLists\.txt:[0-9]+ \(include\)$ diff --git a/Tests/RunCMake/include/CMP0146-NEW-name.cmake b/Tests/RunCMake/include/CMP0146-NEW-name.cmake new file mode 100644 index 0000000..feedc6f --- /dev/null +++ b/Tests/RunCMake/include/CMP0146-NEW-name.cmake @@ -0,0 +1,2 @@ +cmake_policy(SET CMP0146 NEW) +include(FindCUDA) diff --git a/Tests/RunCMake/include/CMP0146-NEW-path-result.txt b/Tests/RunCMake/include/CMP0146-NEW-path-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/include/CMP0146-NEW-path-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/include/CMP0146-NEW-path-stderr.txt b/Tests/RunCMake/include/CMP0146-NEW-path-stderr.txt new file mode 100644 index 0000000..916672b --- /dev/null +++ b/Tests/RunCMake/include/CMP0146-NEW-path-stderr.txt @@ -0,0 +1,6 @@ +^CMake Error at [^ +]*/Modules/FindCUDA.cmake:[0-9]+ \(message\): + The FindCUDA module has been removed by policy CMP0146\. +Call Stack \(most recent call first\): + CMP0146-NEW-path\.cmake:[0-9]+ \(include\) + CMakeLists\.txt:[0-9]+ \(include\)$ diff --git a/Tests/RunCMake/include/CMP0146-NEW-path.cmake b/Tests/RunCMake/include/CMP0146-NEW-path.cmake new file mode 100644 index 0000000..6768d4d --- /dev/null +++ b/Tests/RunCMake/include/CMP0146-NEW-path.cmake @@ -0,0 +1,2 @@ +cmake_policy(SET CMP0146 NEW) +include(${CMAKE_ROOT}/Modules/FindCUDA.cmake) diff --git a/Tests/RunCMake/include/CMP0146-OLD.cmake b/Tests/RunCMake/include/CMP0146-OLD.cmake new file mode 100644 index 0000000..654cdf7 --- /dev/null +++ b/Tests/RunCMake/include/CMP0146-OLD.cmake @@ -0,0 +1,7 @@ +cmake_policy(SET CMP0146 OLD) +set(_FindCUDA_testing 1) +include(FindCUDA) + +if(NOT _FindCUDA_included) + message(FATAL_ERROR "FindCUDA.cmake not included") +endif() diff --git a/Tests/RunCMake/include/CMP0146-WARN-stderr.txt b/Tests/RunCMake/include/CMP0146-WARN-stderr.txt new file mode 100644 index 0000000..aaaf1dc --- /dev/null +++ b/Tests/RunCMake/include/CMP0146-WARN-stderr.txt @@ -0,0 +1,8 @@ +^CMake Warning \(dev\) at CMP0146-WARN\.cmake:[0-9]+ \(include\): + Policy CMP0146 is not set: The FindCUDA module is removed\. Run "cmake + --help-policy CMP0146" for policy details\. Use the cmake_policy command to + set the policy and suppress this warning\. + +Call Stack \(most recent call first\): + CMakeLists\.txt:[0-9]+ \(include\) +This warning is for project developers\. Use -Wno-dev to suppress it\.$ diff --git a/Tests/RunCMake/include/CMP0146-WARN.cmake b/Tests/RunCMake/include/CMP0146-WARN.cmake new file mode 100644 index 0000000..bce1ae8 --- /dev/null +++ b/Tests/RunCMake/include/CMP0146-WARN.cmake @@ -0,0 +1,7 @@ +# Do not set CMP0146. +set(_FindCUDA_testing 1) +include(FindCUDA) + +if(NOT _FindCUDA_included) + message(FATAL_ERROR "FindCUDA.cmake not included") +endif() diff --git a/Tests/RunCMake/include/CMakeLists.txt b/Tests/RunCMake/include/CMakeLists.txt index 4b3de84..93ee9df 100644 --- a/Tests/RunCMake/include/CMakeLists.txt +++ b/Tests/RunCMake/include/CMakeLists.txt @@ -1,3 +1,3 @@ -cmake_minimum_required(VERSION 2.8.12) +cmake_minimum_required(VERSION 3.5) project(${RunCMake_TEST} NONE) include(${RunCMake_TEST}.cmake) diff --git a/Tests/RunCMake/include/EmptyString-stderr.txt b/Tests/RunCMake/include/EmptyString-stderr.txt index 006c647..dab16ea 100644 --- a/Tests/RunCMake/include/EmptyString-stderr.txt +++ b/Tests/RunCMake/include/EmptyString-stderr.txt @@ -1,5 +1,5 @@ -CMake Warning \(dev\) at EmptyString.cmake:1 \(include\): +^CMake Warning \(dev\) at EmptyString\.cmake:1 \(include\): include\(\) given empty file name \(ignored\). Call Stack \(most recent call first\): - CMakeLists.txt:3 \(include\) -This warning is for project developers. Use -Wno-dev to suppress it. + CMakeLists\.txt:3 \(include\) +This warning is for project developers\. Use -Wno-dev to suppress it\.$ diff --git a/Tests/RunCMake/include/EmptyStringOptional-stderr.txt b/Tests/RunCMake/include/EmptyStringOptional-stderr.txt index b61c679..1b763f2 100644 --- a/Tests/RunCMake/include/EmptyStringOptional-stderr.txt +++ b/Tests/RunCMake/include/EmptyStringOptional-stderr.txt @@ -1,5 +1,5 @@ -CMake Warning \(dev\) at EmptyStringOptional.cmake:1 \(include\): +^CMake Warning \(dev\) at EmptyStringOptional\.cmake:1 \(include\): include\(\) given empty file name \(ignored\). Call Stack \(most recent call first\): - CMakeLists.txt:3 \(include\) -This warning is for project developers. Use -Wno-dev to suppress it. + CMakeLists\.txt:3 \(include\) +This warning is for project developers\. Use -Wno-dev to suppress it\.$ diff --git a/Tests/RunCMake/include/ExportExportInclude-stderr.txt b/Tests/RunCMake/include/ExportExportInclude-stderr.txt index 6d5c02f..22bf7a1 100644 --- a/Tests/RunCMake/include/ExportExportInclude-stderr.txt +++ b/Tests/RunCMake/include/ExportExportInclude-stderr.txt @@ -1,6 +1,7 @@ -CMake Error at ExportExportInclude.cmake:6 \(include\): +^CMake Error at ExportExportInclude.cmake:6 \(include\): include could not find requested file: - .*/Tests/RunCMake/include/ExportExportInclude-build/theTargets.cmake + [^ +]*/Tests/RunCMake/include/ExportExportInclude-build/theTargets\.cmake Call Stack \(most recent call first\): - CMakeLists.txt:3 \(include\) + CMakeLists\.txt:3 \(include\)$ diff --git a/Tests/RunCMake/include/IncludeIsDirectory-stderr.txt b/Tests/RunCMake/include/IncludeIsDirectory-stderr.txt index 5735c29..6ce934d 100644 --- a/Tests/RunCMake/include/IncludeIsDirectory-stderr.txt +++ b/Tests/RunCMake/include/IncludeIsDirectory-stderr.txt @@ -1,6 +1,7 @@ -CMake Error at IncludeIsDirectory.cmake:1 \(include\): +^CMake Error at IncludeIsDirectory.cmake:1 \(include\): include requested file is a directory: - .*/Tests/RunCMake/include/IncludeIsDirectory-build + [^ +]*/Tests/RunCMake/include/IncludeIsDirectory-build Call Stack \(most recent call first\): - CMakeLists.txt:3 \(include\) + CMakeLists\.txt:3 \(include\)$ diff --git a/Tests/RunCMake/include/IncludeMalformed-stderr.txt b/Tests/RunCMake/include/IncludeMalformed-stderr.txt index fc75549..e34e9bb 100644 --- a/Tests/RunCMake/include/IncludeMalformed-stderr.txt +++ b/Tests/RunCMake/include/IncludeMalformed-stderr.txt @@ -1,13 +1,12 @@ -CMake Error at malformedInclude.cmake:1: - Parse error. Function missing ending "\)". End of file reached. +^CMake Error at malformedInclude\.cmake:1: + Parse error\. Function missing ending "\)"\. End of file reached\. Call Stack \(most recent call first\): - IncludeMalformed.cmake:1 \(include\) - CMakeLists.txt:3 \(include\) - - -CMake Error at IncludeMalformed.cmake:1 \(include\): + IncludeMalformed\.cmake:1 \(include\) + CMakeLists\.txt:3 \(include\) ++ +CMake Error at IncludeMalformed\.cmake:1 \(include\): include could not load requested file: - malformedInclude.cmake + malformedInclude\.cmake Call Stack \(most recent call first\): - CMakeLists.txt:3 \(include\) + CMakeLists\.txt:3 \(include\)$ diff --git a/Tests/RunCMake/include/RunCMakeTest.cmake b/Tests/RunCMake/include/RunCMakeTest.cmake index 8fb7201..b6fdb54 100644 --- a/Tests/RunCMake/include/RunCMakeTest.cmake +++ b/Tests/RunCMake/include/RunCMakeTest.cmake @@ -7,3 +7,8 @@ run_cmake(CMP0024-NEW) run_cmake(ExportExportInclude) run_cmake(IncludeIsDirectory) run_cmake(IncludeMalformed) + +run_cmake(CMP0146-OLD) +run_cmake(CMP0146-WARN) +run_cmake(CMP0146-NEW-name) +run_cmake(CMP0146-NEW-path) diff --git a/Tests/RunCMake/install/RunCMakeTest.cmake b/Tests/RunCMake/install/RunCMakeTest.cmake index e5a0413..efafdd1 100644 --- a/Tests/RunCMake/install/RunCMakeTest.cmake +++ b/Tests/RunCMake/install/RunCMakeTest.cmake @@ -121,6 +121,10 @@ run_install_test(FILES-OPTIONAL) run_install_test(DIRECTORY-OPTIONAL) run_install_test(TARGETS-Defaults) +if(CMAKE_SYSTEM_NAME STREQUAL "Linux") + run_install_test(TARGETS-NAMELINK-No-Tweak) +endif() + set(RunCMake_TEST_OPTIONS "-DCMAKE_INSTALL_BINDIR:PATH=mybin" "-DCMAKE_INSTALL_LIBDIR:PATH=mylib" diff --git a/Tests/RunCMake/install/TARGETS-NAMELINK-No-Tweak.cmake b/Tests/RunCMake/install/TARGETS-NAMELINK-No-Tweak.cmake new file mode 100644 index 0000000..879f4b8 --- /dev/null +++ b/Tests/RunCMake/install/TARGETS-NAMELINK-No-Tweak.cmake @@ -0,0 +1,20 @@ +enable_language(C) + +add_library(foo SHARED obj1.c) +set_target_properties(foo PROPERTIES + VERSION 1.0 + SOVERSION 1 + INSTALL_RPATH "$ORIGIN" + ) +install(TARGETS foo DESTINATION lib) + +# Replace the .so "namelink" symlink with a linker script. +# It is no longer a symlink, so any install tweaks would break. +# This verifies that no install tweaks are added for the namelink. +set(linker_script "INPUT($<TARGET_SONAME_FILE_NAME:foo>)") +add_custom_command(TARGET foo POST_BUILD + COMMAND "${CMAKE_COMMAND}" -E remove "$<TARGET_LINKER_FILE:foo>" + COMMAND "${CMAKE_COMMAND}" -E echo "${linker_script}" > "$<TARGET_LINKER_FILE:foo>" + COMMENT "Generating linker script: '${linker_script}' as file $<TARGET_LINKER_FILE:foo>" + VERBATIM + ) diff --git a/Tests/RunCMake/showIncludes.c b/Tests/RunCMake/showIncludes.c index 4ea2bcc..5afe04a 100644 --- a/Tests/RunCMake/showIncludes.c +++ b/Tests/RunCMake/showIncludes.c @@ -28,6 +28,15 @@ int main() printf("OEM code page: %u\n", GetOEMCP()); printf("VSLANG: %s\n", vslang); + // clang-cl (special case for test, not a real VS value). + if (strcmp(vslang, "clang-cl") == 0) { + if (cp == 437 || cp == 65001) { + printf("Note: including file: ./foo.h\n"); + return 0; + } + } + + // German. if (strcmp(vslang, "1031") == 0) { if (cp == 437 || cp == 65001) { printf("Hinweis: Einlesen der Datei: C:\\foo.h\n"); @@ -35,6 +44,7 @@ int main() } } + // English. if (strcmp(vslang, "1033") == 0) { if (cp == 437 || cp == 65001) { printf("Note: including file: C:\\foo.h\n"); @@ -42,6 +52,7 @@ int main() } } + // French. if (strcmp(vslang, "1036") == 0) { if (cp == 437 || cp == 863) { printf("Remarque\xff: inclusion du fichier\xff: C:\\foo.h\n"); @@ -53,6 +64,7 @@ int main() } } + // Italian. if (strcmp(vslang, "1040") == 0) { if (cp == 437 || cp == 65001) { printf("Nota: file incluso C:\\foo.h\n"); @@ -60,6 +72,7 @@ int main() } } + // Japanese. if (strcmp(vslang, "1041") == 0) { if (cp == 932) { printf("\x83\x81\x83\x82: " @@ -75,6 +88,7 @@ int main() } } + // Chinese. if (strcmp(vslang, "2052") == 0) { if (cp == 54936 || cp == 936) { printf("\xd7\xa2\xd2\xe2: " diff --git a/Tests/RunCMake/target_sources/FileSetDirect-stderr.txt b/Tests/RunCMake/target_sources/FileSetDirect-stderr.txt index c1f7635..06458b9 100644 --- a/Tests/RunCMake/target_sources/FileSetDirect-stderr.txt +++ b/Tests/RunCMake/target_sources/FileSetDirect-stderr.txt @@ -3,9 +3,9 @@ CMake Error at FileSetDirect.cmake:3 \(add_library\): FILE_SET - Tried extensions .c .C .c\+\+ .cc .cpp .cxx .cu .mpp .m .M .mm .ixx .cppm .h - .hh .h\+\+ .hm .hpp .hxx .in .txx .f .F .for .f77 .f90 .f95 .f03 .hip .ispc - + Tried extensions ([^ +]+ +)+ Hint: the FILE_SET keyword may only appear after a visibility specifier or another FILE_SET within the target_sources\(\) command. Call Stack \(most recent call first\): diff --git a/Tests/RunCMake/target_sources/FileSetWrongSyntax-stderr.txt b/Tests/RunCMake/target_sources/FileSetWrongSyntax-stderr.txt index abfbe29..01db002 100644 --- a/Tests/RunCMake/target_sources/FileSetWrongSyntax-stderr.txt +++ b/Tests/RunCMake/target_sources/FileSetWrongSyntax-stderr.txt @@ -3,9 +3,9 @@ CMake Error at FileSetWrongSyntax.cmake:4 \(target_sources\): FILE_SET - Tried extensions .c .C .c\+\+ .cc .cpp .cxx .cu .mpp .m .M .mm .ixx .cppm .h - .hh .h\+\+ .hm .hpp .hxx .in .txx .f .F .for .f77 .f90 .f95 .f03 .hip .ispc - + Tried extensions ([^ +]+ +)+ Hint: the FILE_SET keyword may only appear after a visibility specifier or another FILE_SET within the target_sources\(\) command. Call Stack \(most recent call first\): diff --git a/Utilities/ClangTidyModule/.gitignore b/Utilities/ClangTidyModule/.gitignore new file mode 100644 index 0000000..e3f48eb --- /dev/null +++ b/Utilities/ClangTidyModule/.gitignore @@ -0,0 +1,8 @@ +/CMakeUserPresets.json + +# Common build directories +/build*/ + +# Visual Studio Code +/.vscode/ +/.cache/ diff --git a/Utilities/Scripts/update-curl.bash b/Utilities/Scripts/update-curl.bash index 791c8b5..5270903 100755 --- a/Utilities/Scripts/update-curl.bash +++ b/Utilities/Scripts/update-curl.bash @@ -8,7 +8,7 @@ readonly name="curl" readonly ownership="Curl Upstream <curl-library@lists.haxx.se>" readonly subtree="Utilities/cmcurl" readonly repo="https://github.com/curl/curl.git" -readonly tag="curl-7_88_1" +readonly tag="curl-8_0_1" readonly shortlog=false readonly paths=" CMake/* diff --git a/Utilities/Sphinx/cmake.py b/Utilities/Sphinx/cmake.py index 47e4909..2ccaf9a 100644 --- a/Utilities/Sphinx/cmake.py +++ b/Utilities/Sphinx/cmake.py @@ -1,103 +1,131 @@ # Distributed under the OSI-approved BSD 3-Clause License. See accompanying # file Copyright.txt or https://cmake.org/licensing for details. +# BEGIN imports + import os import re +from dataclasses import dataclass +from typing import Any, List, Tuple, Type, cast + +import sphinx + +from docutils.utils.code_analyzer import Lexer, LexerError +from docutils.parsers.rst import Directive, directives +from docutils.transforms import Transform +from docutils.nodes import Element, Node, TextElement, system_message +from docutils import io, nodes + +from sphinx.directives import ObjectDescription, nl_escape_re +from sphinx.domains import Domain, ObjType +from sphinx.roles import XRefRole +from sphinx.util.docutils import ReferenceRole +from sphinx.util.nodes import make_refnode +from sphinx.util import logging, ws_re +from sphinx import addnodes + +# END imports + +# %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +# BEGIN pygments tweaks + # Override much of pygments' CMakeLexer. # We need to parse CMake syntax definitions, not CMake code. # For hard test cases that use much of the syntax below, see -# - module/FindPkgConfig.html (with "glib-2.0>=2.10 gtk+-2.0" and similar) -# - module/ExternalProject.html (with http:// https:// git@; also has command options -E --build) -# - manual/cmake-buildsystem.7.html (with nested $<..>; relative and absolute paths, "::") +# - module/FindPkgConfig.html +# (with "glib-2.0>=2.10 gtk+-2.0" and similar) +# - module/ExternalProject.html +# (with http:// https:// git@; also has command options -E --build) +# - manual/cmake-buildsystem.7.html +# (with nested $<..>; relative and absolute paths, "::") from pygments.lexers import CMakeLexer -from pygments.token import Name, Operator, Punctuation, String, Text, Comment, Generic, Whitespace, Number +from pygments.token import (Comment, Name, Number, Operator, Punctuation, + String, Text, Whitespace) from pygments.lexer import bygroups # Notes on regular expressions below: # - [\.\+-] are needed for string constants like gtk+-2.0 -# - Unix paths are recognized by '/'; support for Windows paths may be added if needed +# - Unix paths are recognized by '/'; support for Windows paths may be added +# if needed # - (\\.) allows for \-escapes (used in manual/cmake-language.7) # - $<..$<..$>..> nested occurrence in cmake-buildsystem -# - Nested variable evaluations are only supported in a limited capacity. Only -# one level of nesting is supported and at most one nested variable can be present. +# - Nested variable evaluations are only supported in a limited capacity. +# Only one level of nesting is supported and at most one nested variable can +# be present. CMakeLexer.tokens["root"] = [ - (r'\b(\w+)([ \t]*)(\()', bygroups(Name.Function, Text, Name.Function), '#push'), # fctn( + # fctn( + (r'\b(\w+)([ \t]*)(\()', + bygroups(Name.Function, Text, Name.Function), '#push'), (r'\(', Name.Function, '#push'), (r'\)', Name.Function, '#pop'), (r'\[', Punctuation, '#push'), (r'\]', Punctuation, '#pop'), (r'[|;,.=*\-]', Punctuation), - (r'\\\\', Punctuation), # used in commands/source_group + # used in commands/source_group + (r'\\\\', Punctuation), (r'[:]', Operator), - (r'[<>]=', Punctuation), # used in FindPkgConfig.cmake - (r'\$<', Operator, '#push'), # $<...> - (r'<[^<|]+?>(\w*\.\.\.)?', Name.Variable), # <expr> - (r'(\$\w*\{)([^\}\$]*)?(?:(\$\w*\{)([^\}]+?)(\}))?([^\}]*?)(\})', # ${..} $ENV{..}, possibly nested - bygroups(Operator, Name.Tag, Operator, Name.Tag, Operator, Name.Tag, Operator)), - (r'([A-Z]+\{)(.+?)(\})', bygroups(Operator, Name.Tag, Operator)), # DATA{ ...} - (r'[a-z]+(@|(://))((\\.)|[\w.+-:/\\])+', Name.Attribute), # URL, git@, ... - (r'/\w[\w\.\+-/\\]*', Name.Attribute), # absolute path + # used in FindPkgConfig.cmake + (r'[<>]=', Punctuation), + # $<...> + (r'\$<', Operator, '#push'), + # <expr> + (r'<[^<|]+?>(\w*\.\.\.)?', Name.Variable), + # ${..} $ENV{..}, possibly nested + (r'(\$\w*\{)([^\}\$]*)?(?:(\$\w*\{)([^\}]+?)(\}))?([^\}]*?)(\})', + bygroups(Operator, Name.Tag, Operator, Name.Tag, Operator, Name.Tag, + Operator)), + # DATA{ ...} + (r'([A-Z]+\{)(.+?)(\})', bygroups(Operator, Name.Tag, Operator)), + # URL, git@, ... + (r'[a-z]+(@|(://))((\\.)|[\w.+-:/\\])+', Name.Attribute), + # absolute path + (r'/\w[\w\.\+-/\\]*', Name.Attribute), (r'/', Name.Attribute), - (r'\w[\w\.\+-]*/[\w.+-/\\]*', Name.Attribute), # relative path - (r'[A-Z]((\\.)|[\w.+-])*[a-z]((\\.)|[\w.+-])*', Name.Builtin), # initial A-Z, contains a-z + # relative path + (r'\w[\w\.\+-]*/[\w.+-/\\]*', Name.Attribute), + # initial A-Z, contains a-z + (r'[A-Z]((\\.)|[\w.+-])*[a-z]((\\.)|[\w.+-])*', Name.Builtin), (r'@?[A-Z][A-Z0-9_]*', Name.Constant), (r'[a-z_]((\\;)|(\\ )|[\w.+-])*', Name.Builtin), (r'[0-9][0-9\.]*', Number), - (r'(?s)"(\\"|[^"])*"', String), # "string" + # "string" + (r'(?s)"(\\"|[^"])*"', String), (r'\.\.\.', Name.Variable), - (r'<', Operator, '#push'), # <..|..> is different from <expr> + # <..|..> is different from <expr> + (r'<', Operator, '#push'), (r'>', Operator, '#pop'), (r'\n', Whitespace), (r'[ \t]+', Whitespace), (r'#.*\n', Comment), - # (r'[^<>\])\}\|$"# \t\n]+', Name.Exception), # fallback, for debugging only + # fallback, for debugging only + # (r'[^<>\])\}\|$"# \t\n]+', Name.Exception), ] -from docutils.parsers.rst import Directive, directives -from docutils.transforms import Transform -from docutils import io, nodes +# END pygments tweaks -from sphinx.directives import ObjectDescription -from sphinx.domains import Domain, ObjType -from sphinx.roles import XRefRole -from sphinx.util.nodes import make_refnode -from sphinx import addnodes +# %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +# Require at least Sphinx 2.x. +assert sphinx.version_info >= (2,) + +logger = logging.getLogger(__name__) + +# RE to split multiple command signatures. +sig_end_re = re.compile(r'(?<=[)])\n') + + +@dataclass +class ObjectEntry: + docname: str + objtype: str + node_id: str + name: str -sphinx_before_1_4 = False -sphinx_before_1_7_2 = False -try: - from sphinx import version_info - if version_info < (1, 4): - sphinx_before_1_4 = True - if version_info < (1, 7, 2): - sphinx_before_1_7_2 = True -except ImportError: - # The `sphinx.version_info` tuple was added in Sphinx v1.2: - sphinx_before_1_4 = True - sphinx_before_1_7_2 = True - -if sphinx_before_1_7_2: - # Monkey patch for sphinx generating invalid content for qcollectiongenerator - # https://github.com/sphinx-doc/sphinx/issues/1435 - from sphinx.util.pycompat import htmlescape - from sphinx.builders.qthelp import QtHelpBuilder - old_build_keywords = QtHelpBuilder.build_keywords - def new_build_keywords(self, title, refs, subitems): - old_items = old_build_keywords(self, title, refs, subitems) - new_items = [] - for item in old_items: - before, rest = item.split("ref=\"", 1) - ref, after = rest.split("\"") - if ("<" in ref and ">" in ref): - new_items.append(before + "ref=\"" + htmlescape(ref) + "\"" + after) - else: - new_items.append(item) - return new_items - QtHelpBuilder.build_keywords = new_build_keywords class CMakeModule(Directive): required_arguments = 1 @@ -112,7 +140,7 @@ class CMakeModule(Directive): def run(self): settings = self.state.document.settings if not settings.file_insertion_enabled: - raise self.warning('"%s" directive disabled.' % self.name) + raise self.warning(f'{self.name!r} directive disabled.') env = self.state.document.settings.env rel_path, path = env.relfn2path(self.arguments[0]) @@ -123,13 +151,12 @@ class CMakeModule(Directive): settings.record_dependencies.add(path) f = io.FileInput(source_path=path, encoding=encoding, error_handler=e_handler) - except UnicodeEncodeError as error: - msg = ('Problems with "%s" directive path:\n' - 'Cannot encode input file path "%s" ' - '(wrong locale?).' % (self.name, path)) + except UnicodeEncodeError: + msg = (f'Problems with {self.name!r} directive path:\n' + f'Cannot encode input file path {path!r} (wrong locale?).') raise self.severe(msg) except IOError as error: - msg = 'Problems with "%s" directive path:\n%s.' % (self.name, error) + msg = f'Problems with {self.name!r} directive path:\n{error}.' raise self.severe(msg) raw_lines = f.read().splitlines() f.close() @@ -149,7 +176,7 @@ class CMakeModule(Directive): # Line mode: check for .rst start (bracket or line) m = self.re_start.match(line) if m: - rst = ']%s]' % m.group('eq') + rst = f']{m.group("eq")}]' line = '' elif line == '#.rst:': rst = '#' @@ -164,21 +191,19 @@ class CMakeModule(Directive): line = '' lines.append(line) if rst is not None and rst != '#': - raise self.warning('"%s" found unclosed bracket "#[%s[.rst:" in %s' % - (self.name, rst[1:-1], path)) + raise self.warning(f'{self.name!r} found unclosed bracket ' + f'"#[{rst[1:-1]}[.rst:" in {path!r}') self.state_machine.insert_input(lines, path) return [] + class _cmake_index_entry: def __init__(self, desc): self.desc = desc - def __call__(self, title, targetid, main = 'main'): - # See https://github.com/sphinx-doc/sphinx/issues/2673 - if sphinx_before_1_4: - return ('pair', u'%s ; %s' % (self.desc, title), targetid, main) - else: - return ('pair', u'%s ; %s' % (self.desc, title), targetid, main, None) + def __call__(self, title, targetid, main='main'): + return ('pair', f'{self.desc} ; {title}', targetid, main, None) + _cmake_index_objs = { 'command': _cmake_index_entry('command'), @@ -200,13 +225,6 @@ _cmake_index_objs = { 'variable': _cmake_index_entry('variable'), } -def _cmake_object_inventory(env, document, line, objtype, targetid): - inv = env.domaindata['cmake']['objects'] - if targetid in inv: - document.reporter.warning( - 'CMake object "%s" also described in "%s".' % - (targetid, env.doc2path(inv[targetid][0])), line=line) - inv[targetid] = (env.docname, objtype) class CMakeTransform(Transform): @@ -234,7 +252,8 @@ class CMakeTransform(Transform): title = False else: for line in f: - if len(line) > 0 and (line[0].isalnum() or line[0] == '<' or line[0] == '$'): + if len(line) > 0 and (line[0].isalnum() or + line[0] == '<' or line[0] == '$'): title = line.rstrip() break f.close() @@ -262,7 +281,7 @@ class CMakeTransform(Transform): if m: title = m.group(1) targetname = title - targetid = '%s:%s' % (objtype, targetname) + targetid = f'{objtype}:{targetname}' targetnode = nodes.target('', '', ids=[targetid]) self.document.note_explicit_target(targetnode) self.document.insert(0, targetnode) @@ -270,72 +289,277 @@ class CMakeTransform(Transform): indexnode = addnodes.index() indexnode['entries'] = [make_index_entry(title, targetid)] self.document.insert(0, indexnode) + # Add to cmake domain object inventory - _cmake_object_inventory(env, self.document, 1, objtype, targetid) + domain = cast(CMakeDomain, env.get_domain('cmake')) + domain.note_object(objtype, targetname, targetid, targetid) + class CMakeObject(ObjectDescription): + def __init__(self, *args, **kwargs): + self.targetname = None + super().__init__(*args, **kwargs) def handle_signature(self, sig, signode): # called from sphinx.directives.ObjectDescription.run() signode += addnodes.desc_name(sig, sig) - if self.objtype == 'genex': - m = CMakeXRefRole._re_genex.match(sig) - if m: - sig = m.group(1) return sig def add_target_and_index(self, name, sig, signode): if self.objtype == 'command': - targetname = name.lower() + targetname = name.lower() + elif self.targetname: + targetname = self.targetname else: - targetname = name - targetid = '%s:%s' % (self.objtype, targetname) + targetname = name + targetid = f'{self.objtype}:{targetname}' if targetid not in self.state.document.ids: signode['names'].append(targetid) signode['ids'].append(targetid) signode['first'] = (not self.names) self.state.document.note_explicit_target(signode) - _cmake_object_inventory(self.env, self.state.document, - self.lineno, self.objtype, targetid) + + domain = cast(CMakeDomain, self.env.get_domain('cmake')) + domain.note_object(self.objtype, targetname, targetid, targetid, + location=signode) make_index_entry = _cmake_index_objs.get(self.objtype) if make_index_entry: self.indexnode['entries'].append(make_index_entry(name, targetid)) -class CMakeXRefRole(XRefRole): +class CMakeGenexObject(CMakeObject): + option_spec = { + 'target': directives.unchanged, + } + + def handle_signature(self, sig, signode): + name = super().handle_signature(sig, signode) + + m = CMakeXRefRole._re_genex.match(sig) + if m: + name = m.group(1) + + return name + + def run(self): + target = self.options.get('target') + if target is not None: + self.targetname = target + + return super().run() + + +class CMakeSignatureObject(CMakeObject): + object_type = 'signature' + + BREAK_ALL = 'all' + BREAK_SMART = 'smart' + BREAK_VERBATIM = 'verbatim' + + BREAK_CHOICES = {BREAK_ALL, BREAK_SMART, BREAK_VERBATIM} + + def break_option(argument): + return directives.choice(argument, CMakeSignatureObject.BREAK_CHOICES) + + option_spec = { + 'target': directives.unchanged, + 'break': break_option, + } + + def _break_signature_all(sig: str) -> str: + return ws_re.sub(' ', sig) + + def _break_signature_verbatim(sig: str) -> str: + lines = [ws_re.sub('\xa0', line.strip()) for line in sig.split('\n')] + return ' '.join(lines) + + def _break_signature_smart(sig: str) -> str: + tokens = [] + for line in sig.split('\n'): + token = '' + delim = '' + + for c in line.strip(): + if len(delim) == 0 and ws_re.match(c): + if len(token): + tokens.append(ws_re.sub('\xa0', token)) + token = '' + else: + if c == '[': + delim += ']' + elif c == '<': + delim += '>' + elif len(delim) and c == delim[-1]: + delim = delim[:-1] + token += c + + if len(token): + tokens.append(ws_re.sub('\xa0', token)) + + return ' '.join(tokens) + + def __init__(self, *args, **kwargs): + self.targetnames = {} + self.break_style = CMakeSignatureObject.BREAK_SMART + super().__init__(*args, **kwargs) + + def get_signatures(self) -> List[str]: + content = nl_escape_re.sub('', self.arguments[0]) + lines = sig_end_re.split(content) + + if self.break_style == CMakeSignatureObject.BREAK_VERBATIM: + fixup = CMakeSignatureObject._break_signature_verbatim + elif self.break_style == CMakeSignatureObject.BREAK_SMART: + fixup = CMakeSignatureObject._break_signature_smart + else: + fixup = CMakeSignatureObject._break_signature_all + + return [fixup(line.strip()) for line in lines] + + def handle_signature(self, sig, signode): + language = 'cmake' + classes = ['code', 'cmake', 'highlight'] + + node = addnodes.desc_name(sig, '', classes=classes) + + try: + tokens = Lexer(sig, language, 'short') + except LexerError as error: + if self.state.document.settings.report_level > 2: + # Silently insert without syntax highlighting. + tokens = Lexer(sig, language, 'none') + else: + raise self.warning(error) + + for classes, value in tokens: + if value == '\xa0': + node += nodes.inline(value, value, classes=['nbsp']) + elif classes: + node += nodes.inline(value, value, classes=classes) + else: + node += nodes.Text(value) + + signode.clear() + signode += node + + return sig + + def add_target_and_index(self, name, sig, signode): + sig = sig.replace('\xa0', ' ') + if sig in self.targetnames: + sigargs = self.targetnames[sig] + else: + def extract_keywords(params): + for p in params: + if p[0].isalpha(): + yield p + else: + return + + keywords = extract_keywords(sig.split('(')[1].split()) + sigargs = ' '.join(keywords) + targetname = sigargs.lower() + targetid = nodes.make_id(targetname) + + if targetid not in self.state.document.ids: + signode['names'].append(targetname) + signode['ids'].append(targetid) + signode['first'] = (not self.names) + self.state.document.note_explicit_target(signode) + + # Register the signature as a command object. + command = sig.split('(')[0].lower() + refname = f'{command}({sigargs})' + refid = f'command:{command}({targetname})' + + domain = cast(CMakeDomain, self.env.get_domain('cmake')) + domain.note_object('command', name=refname, target_id=refid, + node_id=targetid, location=signode) + + def run(self): + self.break_style = CMakeSignatureObject.BREAK_ALL + + targets = self.options.get('target') + if targets is not None: + signatures = self.get_signatures() + targets = [t.strip() for t in targets.split('\n')] + for signature, target in zip(signatures, targets): + self.targetnames[signature] = target + + self.break_style = ( + self.options.get('break', CMakeSignatureObject.BREAK_SMART)) + + return super().run() + + +class CMakeReferenceRole: # See sphinx.util.nodes.explicit_title_re; \x00 escapes '<'. _re = re.compile(r'^(.+?)(\s*)(?<!\x00)<(.*?)>$', re.DOTALL) + + @staticmethod + def _escape_angle_brackets(text: str) -> str: + # CMake cross-reference targets frequently contain '<' so escape + # any explicit `<target>` with '<' not preceded by whitespace. + while True: + m = CMakeReferenceRole._re.match(text) + if m and len(m.group(2)) == 0: + text = f'{m.group(1)}\x00<{m.group(3)}>' + else: + break + return text + + def __class_getitem__(cls, parent: Any): + class Class(parent): + def __call__(self, name: str, rawtext: str, text: str, + *args, **kwargs + ) -> Tuple[List[Node], List[system_message]]: + text = CMakeReferenceRole._escape_angle_brackets(text) + return super().__call__(name, rawtext, text, *args, **kwargs) + return Class + + +class CMakeCRefRole(CMakeReferenceRole[ReferenceRole]): + nodeclass: Type[Element] = nodes.reference + innernodeclass: Type[TextElement] = nodes.literal + classes: List[str] = ['cmake', 'literal'] + + def run(self) -> Tuple[List[Node], List[system_message]]: + refnode = self.nodeclass(self.rawtext) + self.set_source_info(refnode) + + refnode['refid'] = nodes.make_id(self.target) + refnode += self.innernodeclass(self.rawtext, self.title, + classes=self.classes) + + return [refnode], [] + + +class CMakeXRefRole(CMakeReferenceRole[XRefRole]): + _re_sub = re.compile(r'^([^()\s]+)\s*\(([^()]*)\)$', re.DOTALL) _re_genex = re.compile(r'^\$<([^<>:]+)(:[^<>]+)?>$', re.DOTALL) _re_guide = re.compile(r'^([^<>/]+)/([^<>]*)$', re.DOTALL) - def __call__(self, typ, rawtext, text, *args, **keys): - # Translate CMake command cross-references of the form: - # `command_name(SUB_COMMAND)` - # to have an explicit target: - # `command_name(SUB_COMMAND) <command_name>` + def __call__(self, typ, rawtext, text, *args, **kwargs): if typ == 'cmake:command': + # Translate a CMake command cross-reference of the form: + # `command_name(SUB_COMMAND)` + # to be its own explicit target: + # `command_name(SUB_COMMAND) <command_name(SUB_COMMAND)>` + # so the XRefRole `fix_parens` option does not add more `()`. m = CMakeXRefRole._re_sub.match(text) if m: - text = '%s <%s>' % (text, m.group(1)) + text = f'{text} <{text}>' elif typ == 'cmake:genex': m = CMakeXRefRole._re_genex.match(text) if m: - text = '%s <%s>' % (text, m.group(1)) + text = f'{text} <{m.group(1)}>' elif typ == 'cmake:guide': m = CMakeXRefRole._re_guide.match(text) if m: - text = '%s <%s>' % (m.group(2), text) - # CMake cross-reference targets frequently contain '<' so escape - # any explicit `<target>` with '<' not preceded by whitespace. - while True: - m = CMakeXRefRole._re.match(text) - if m and len(m.group(2)) == 0: - text = '%s\x00<%s>' % (m.group(1), m.group(3)) - else: - break - return XRefRole.__call__(self, typ, rawtext, text, *args, **keys) + text = f'{m.group(2)} <{text}>' + return super().__call__(typ, rawtext, text, *args, **kwargs) # We cannot insert index nodes using the result_nodes method # because CMakeXRefRole is processed before substitution_reference @@ -348,6 +572,7 @@ class CMakeXRefRole(XRefRole): # def result_nodes(self, document, env, node, is_ref): # pass + class CMakeXRefTransform(Transform): # Run this transform early since we insert nodes we want @@ -374,9 +599,13 @@ class CMakeXRefTransform(Transform): # Do not index cross-references to guide sections. continue - targetnum = env.new_serialno('index-%s:%s' % (objtype, objname)) + if objtype == 'command': + # Index signature references to their parent command. + objname = objname.split('(')[0].lower() + + targetnum = env.new_serialno(f'index-{objtype}:{objname}') - targetid = 'index-%s-%s:%s' % (targetnum, objtype, objname) + targetid = f'index-{targetnum}-{objtype}:{objname}' targetnode = nodes.target('', '', ids=[targetid]) self.document.note_explicit_target(targetnode) @@ -384,6 +613,7 @@ class CMakeXRefTransform(Transform): indexnode['entries'] = [make_index_entry(objname, targetid, '')] ref.replace_self([indexnode, targetnode, ref]) + class CMakeDomain(Domain): """CMake domain.""" name = 'cmake' @@ -410,23 +640,14 @@ class CMakeDomain(Domain): directives = { 'command': CMakeObject, 'envvar': CMakeObject, - 'genex': CMakeObject, + 'genex': CMakeGenexObject, + 'signature': CMakeSignatureObject, 'variable': CMakeObject, - # Other object types cannot be created except by the CMakeTransform - # 'generator': CMakeObject, - # 'module': CMakeObject, - # 'policy': CMakeObject, - # 'prop_cache': CMakeObject, - # 'prop_dir': CMakeObject, - # 'prop_gbl': CMakeObject, - # 'prop_inst': CMakeObject, - # 'prop_sf': CMakeObject, - # 'prop_test': CMakeObject, - # 'prop_tgt': CMakeObject, - # 'manual': CMakeObject, + # Other `object_types` cannot be created except by the `CMakeTransform` } roles = { - 'command': CMakeXRefRole(fix_parens = True, lowercase = True), + 'cref': CMakeCRefRole(), + 'command': CMakeXRefRole(fix_parens=True, lowercase=True), 'cpack_gen': CMakeXRefRole(), 'envvar': CMakeXRefRole(), 'generator': CMakeXRefRole(), @@ -450,25 +671,47 @@ class CMakeDomain(Domain): def clear_doc(self, docname): to_clear = set() - for fullname, (fn, _) in self.data['objects'].items(): - if fn == docname: + for fullname, obj in self.data['objects'].items(): + if obj.docname == docname: to_clear.add(fullname) for fullname in to_clear: del self.data['objects'][fullname] def resolve_xref(self, env, fromdocname, builder, typ, target, node, contnode): - targetid = '%s:%s' % (typ, target) + targetid = f'{typ}:{target}' obj = self.data['objects'].get(targetid) + + if obj is None and typ == 'command': + # If 'command(args)' wasn't found, try just 'command'. + # TODO: remove this fallback? warn? + # logger.warning(f'no match for {targetid}') + command = target.split('(')[0] + targetid = f'{typ}:{command}' + obj = self.data['objects'].get(targetid) + if obj is None: # TODO: warn somehow? return None - return make_refnode(builder, fromdocname, obj[0], targetid, + + return make_refnode(builder, fromdocname, obj.docname, obj.node_id, contnode, target) + def note_object(self, objtype: str, name: str, target_id: str, + node_id: str, location: Any = None): + if target_id in self.data['objects']: + other = self.data['objects'][target_id].docname + logger.warning( + f'CMake object {target_id!r} also described in {other!r}', + location=location) + + self.data['objects'][target_id] = ObjectEntry( + self.env.docname, objtype, node_id, name) + def get_objects(self): - for refname, (docname, type) in self.data['objects'].items(): - yield (refname, refname, type, docname, refname, 1) + for refname, obj in self.data['objects'].items(): + yield (refname, obj.name, obj.objtype, obj.docname, obj.node_id, 1) + def setup(app): app.add_directive('cmake-module', CMakeModule) diff --git a/Utilities/Sphinx/static/cmake.css b/Utilities/Sphinx/static/cmake.css index 324cd92..6303cb1 100644 --- a/Utilities/Sphinx/static/cmake.css +++ b/Utilities/Sphinx/static/cmake.css @@ -17,6 +17,45 @@ div.sphinxsidebarwrapper { background-color: #dfdfdf; } +/* Apply <pre> style (from classic.css) to signature directive argument. */ +.signature .sig { + padding: 5px; + background-color: #eeeeee; + color: #333333; + line-height: 120%; + border: 1px solid #ac9; + border-left: none; + border-right: none; +} + +/* Add additional styling to signature directive argument. */ +.signature .sig { + margin-bottom: 5px; + padding-left: calc(5px + 3em); + text-indent: -3em; + font-family: monospace; +} + +.signature .sig .code.sig-name { + font-weight: normal; +} + +/* Implement non-breaking spaces in signatures. */ +.nbsp { + white-space: nowrap; +} + +/* Add hanging indent to version-{added,changed} content. */ +div .versionadded > *, +div .versionchanged > * { + padding-left: 2em; +} + +div.versionadded > :first-child, +div.versionchanged > :first-child { + text-indent: -2em; +} + /* Remove unwanted margin in case list item contains a div-wrapping directive like `.. versionadded` or `.. deprecated`. */ dd > :first-child > p { diff --git a/Utilities/cmcurl/CMake/FindNGTCP2.cmake b/Utilities/cmcurl/CMake/FindNGTCP2.cmake index 9f4e9f2..ff0d49e 100644 --- a/Utilities/cmcurl/CMake/FindNGTCP2.cmake +++ b/Utilities/cmcurl/CMake/FindNGTCP2.cmake @@ -71,7 +71,7 @@ endif() if(NGTCP2_FIND_COMPONENTS) set(NGTCP2_CRYPTO_BACKEND "") foreach(component IN LISTS NGTCP2_FIND_COMPONENTS) - if(component MATCHES "^(BoringSSL|OpenSSL|GnuTLS)") + if(component MATCHES "^(BoringSSL|OpenSSL|wolfSSL|GnuTLS)") if(NGTCP2_CRYPTO_BACKEND) message(FATAL_ERROR "NGTCP2: Only one crypto library can be selected") endif() diff --git a/Utilities/cmcurl/CMake/Platforms/WindowsCache.cmake b/Utilities/cmcurl/CMake/Platforms/WindowsCache.cmake index cef31b5..3771237 100644 --- a/Utilities/cmcurl/CMake/Platforms/WindowsCache.cmake +++ b/Utilities/cmcurl/CMake/Platforms/WindowsCache.cmake @@ -29,7 +29,6 @@ if(NOT UNIX) set(HAVE_ARPA_INET_H 0) set(HAVE_FCNTL_H 1) - set(HAVE_INTTYPES_H 0) set(HAVE_IO_H 1) set(HAVE_NETDB_H 0) set(HAVE_NETINET_IN_H 0) @@ -37,7 +36,6 @@ if(NOT UNIX) set(HAVE_PWD_H 0) set(HAVE_SETJMP_H 1) set(HAVE_SIGNAL_H 1) - set(HAVE_STDINT_H 0) set(HAVE_STDLIB_H 1) set(HAVE_STRINGS_H 0) set(HAVE_STRING_H 1) diff --git a/Utilities/cmcurl/CMakeLists.txt b/Utilities/cmcurl/CMakeLists.txt index 6fc316d..dcade3d 100644 --- a/Utilities/cmcurl/CMakeLists.txt +++ b/Utilities/cmcurl/CMakeLists.txt @@ -197,7 +197,7 @@ endif() # HAVE_RAND_EGD: `RAND_egd` present in OpenSSL # HAVE_BORINGSSL: OpenSSL is BoringSSL # HAVE_PK11_CREATEMANAGEDGENERICOBJECTL: `PK11_CreateManagedGenericObject` present in NSS -# HAVE_SSL_CTX_SET_QUIC_METHOD: `SSL_CTX_set_quic_method` present in OpenSSL +# HAVE_SSL_CTX_SET_QUIC_METHOD: `SSL_CTX_set_quic_method` present in OpenSSL/wolfSSL # HAVE_QUICHE_CONN_SET_QLOG_FD: `quiche_conn_set_qlog_fd` present in QUICHE # HAVE_ZSTD_CREATEDSTREAM: `ZSTD_createDStream` present in Zstd # @@ -523,7 +523,7 @@ if(APPLE) endif() if(WIN32) cmake_dependent_option(CURL_USE_SCHANNEL "enable Windows native SSL/TLS" OFF CURL_ENABLE_SSL OFF) - cmake_dependent_option(CURL_WINDOWS_SSPI "Use windows libraries to allow NTLM authentication without openssl" ON + cmake_dependent_option(CURL_WINDOWS_SSPI "Use windows libraries to allow NTLM authentication without OpenSSL" ON CURL_USE_SCHANNEL OFF) endif() cmake_dependent_option(CURL_USE_MBEDTLS "Enable mbedTLS for SSL/TLS" OFF CURL_ENABLE_SSL OFF) @@ -583,6 +583,62 @@ if(use_core_foundation) list(APPEND CURL_LIBS "-framework CoreFoundation") endif() +# Keep compression lib detection before TLS detection, which +# might depend on it. + +set(HAVE_LIBZ OFF) +set(USE_ZLIB OFF) +find_package(ZLIB) +if(ZLIB_FOUND) + set(HAVE_LIBZ ON) + set(USE_ZLIB ON) + + # Depend on ZLIB via imported targets if supported by the running + # version of CMake. This allows our dependents to get our dependencies + # transitively. + if(NOT CMAKE_VERSION VERSION_LESS 3.4) + if(CMAKE_USE_SYSTEM_ZLIB) + list(APPEND CURL_LIBS ZLIB::ZLIB) + else() + list(APPEND CURL_LIBS cmzlib) + endif() + else() + list(APPEND CURL_LIBS ${ZLIB_LIBRARIES}) + include_directories(${ZLIB_INCLUDE_DIRS}) + list(APPEND CMAKE_REQUIRED_INCLUDES ${ZLIB_INCLUDE_DIRS}) + endif() +endif() + +option(CURL_BROTLI "Set to ON to enable building curl with brotli support." OFF) +set(HAVE_BROTLI OFF) +if(CURL_BROTLI) + find_package(Brotli QUIET) + if(BROTLI_FOUND) + set(HAVE_BROTLI ON) + list(APPEND CURL_LIBS ${BROTLI_LIBRARIES}) + include_directories(${BROTLI_INCLUDE_DIRS}) + list(APPEND CMAKE_REQUIRED_INCLUDES ${BROTLI_INCLUDE_DIRS}) + endif() +endif() + +option(CURL_ZSTD "Set to ON to enable building curl with zstd support." OFF) +set(HAVE_ZSTD OFF) +if(CURL_ZSTD) + find_package(Zstd REQUIRED) + if (NOT DEFINED HAVE_ZSTD_CREATEDSTREAM) + cmake_push_check_state() + set(CMAKE_REQUIRED_INCLUDES ${Zstd_INCLUDE_DIRS}) + set(CMAKE_REQUIRED_LIBRARIES ${Zstd_LIBRARIES}) + check_symbol_exists(ZSTD_createDStream "zstd.h" HAVE_ZSTD_CREATEDSTREAM) + cmake_pop_check_state() + endif() + if(Zstd_FOUND AND HAVE_ZSTD_CREATEDSTREAM) + set(HAVE_ZSTD ON) + list(APPEND CURL_LIBS ${Zstd_LIBRARIES}) + include_directories(${Zstd_INCLUDE_DIRS}) + endif() +endif() + if(CURL_USE_OPENSSL) find_package(OpenSSL) if(NOT OpenSSL_FOUND) @@ -660,23 +716,39 @@ if(USE_NGHTTP2) endif() function(CheckQuicSupportInOpenSSL) - # Be sure that the OpenSSL library actually supports QUIC. + # Be sure that the OpenSSL/wolfSSL library actually supports QUIC. if(NOT DEFINED HAVE_SSL_CTX_SET_QUIC_METHOD) cmake_push_check_state() - set(CMAKE_REQUIRED_INCLUDES "${OPENSSL_INCLUDE_DIR}") - set(CMAKE_REQUIRED_LIBRARIES "${OPENSSL_LIBRARIES}") - check_symbol_exists(SSL_CTX_set_quic_method "openssl/ssl.h" HAVE_SSL_CTX_SET_QUIC_METHOD) + if(USE_WOLFSSL) + set(CMAKE_REQUIRED_INCLUDES "${WolfSSL_INCLUDE_DIRS}") + set(CMAKE_REQUIRED_LIBRARIES "${WolfSSL_LIBRARIES}") + if(HAVE_LIBZ) + list(APPEND CMAKE_REQUIRED_INCLUDES "${ZLIB_INCLUDE_DIRS}") + list(APPEND CMAKE_REQUIRED_LIBRARIES "${ZLIB_LIBRARIES}") + endif() + if(WIN32) + list(APPEND CMAKE_REQUIRED_LIBRARIES "crypt32") + endif() + list(APPEND CMAKE_REQUIRED_DEFINITIONS -DHAVE_UINTPTR_T) # to pull in stdint.h (as of wolfSSL v5.5.4) + check_symbol_exists(wolfSSL_set_quic_method "wolfssl/options.h;wolfssl/openssl/ssl.h" HAVE_SSL_CTX_SET_QUIC_METHOD) + else() + set(CMAKE_REQUIRED_INCLUDES "${OPENSSL_INCLUDE_DIR}") + set(CMAKE_REQUIRED_LIBRARIES "${OPENSSL_LIBRARIES}") + check_symbol_exists(SSL_CTX_set_quic_method "openssl/ssl.h" HAVE_SSL_CTX_SET_QUIC_METHOD) + endif() cmake_pop_check_state() endif() if(NOT HAVE_SSL_CTX_SET_QUIC_METHOD) - message(FATAL_ERROR "QUIC support is missing in OpenSSL/BoringSSL. Try setting -DOPENSSL_ROOT_DIR") + message(FATAL_ERROR "QUIC support is missing in OpenSSL/BoringSSL/wolfSSL. Try setting -DOPENSSL_ROOT_DIR") endif() endfunction() option(USE_NGTCP2 "Use ngtcp2 and nghttp3 libraries for HTTP/3 support" OFF) if(USE_NGTCP2) - if(USE_OPENSSL) - if(HAVE_BORINGSSL) + if(USE_OPENSSL OR USE_WOLFSSL) + if(USE_WOLFSSL) + find_package(NGTCP2 REQUIRED wolfSSL) + elseif(HAVE_BORINGSSL) find_package(NGTCP2 REQUIRED BoringSSL) else() find_package(NGTCP2 REQUIRED OpenSSL) @@ -686,7 +758,7 @@ if(USE_NGTCP2) # TODO add GnuTLS support as vtls library. find_package(NGTCP2 REQUIRED GnuTLS) else() - message(FATAL_ERROR "ngtcp2 requires OpenSSL or GnuTLS") + message(FATAL_ERROR "ngtcp2 requires OpenSSL, wolfSSL or GnuTLS") endif() set(USE_NGTCP2 ON) include_directories(${NGTCP2_INCLUDE_DIRS}) @@ -734,6 +806,8 @@ if(NOT CURL_DISABLE_LDAP) check_library_exists_concat("wldap32" cldap_open HAVE_WLDAP32) if(NOT HAVE_WLDAP32) set(USE_WIN32_LDAP OFF) + elseif(NOT CURL_DISABLE_LDAPS) + set(HAVE_LDAP_SSL ON) endif() endif() endif() @@ -849,56 +923,6 @@ if(WIN32) endif() endif() -set(HAVE_LIBZ OFF) -set(USE_ZLIB OFF) -#optional_dependency(ZLIB) -find_package(ZLIB) -if(ZLIB_FOUND) - set(HAVE_LIBZ ON) - set(USE_ZLIB ON) - - # Depend on ZLIB via imported targets if supported by the running - # version of CMake. This allows our dependents to get our dependencies - # transitively. - if(NOT CMAKE_VERSION VERSION_LESS 3.4) - list(APPEND CURL_LIBS ZLIB::ZLIB) - else() - list(APPEND CURL_LIBS ${ZLIB_LIBRARIES}) - include_directories(${ZLIB_INCLUDE_DIRS}) - list(APPEND CMAKE_REQUIRED_INCLUDES ${ZLIB_INCLUDE_DIRS}) - endif() -endif() - -option(CURL_BROTLI "Set to ON to enable building curl with brotli support." OFF) -set(HAVE_BROTLI OFF) -if(CURL_BROTLI) - find_package(Brotli QUIET) - if(BROTLI_FOUND) - set(HAVE_BROTLI ON) - list(APPEND CURL_LIBS ${BROTLI_LIBRARIES}) - include_directories(${BROTLI_INCLUDE_DIRS}) - list(APPEND CMAKE_REQUIRED_INCLUDES ${BROTLI_INCLUDE_DIRS}) - endif() -endif() - -option(CURL_ZSTD "Set to ON to enable building curl with zstd support." OFF) -set(HAVE_ZSTD OFF) -if(CURL_ZSTD) - find_package(Zstd REQUIRED) - if (NOT DEFINED HAVE_ZSTD_CREATEDSTREAM) - cmake_push_check_state() - set(CMAKE_REQUIRED_INCLUDES ${Zstd_INCLUDE_DIRS}) - set(CMAKE_REQUIRED_LIBRARIES ${Zstd_LIBRARIES}) - check_symbol_exists(ZSTD_createDStream "zstd.h" HAVE_ZSTD_CREATEDSTREAM) - cmake_pop_check_state() - endif() - if(Zstd_FOUND AND HAVE_ZSTD_CREATEDSTREAM) - set(HAVE_ZSTD ON) - list(APPEND CURL_LIBS ${Zstd_LIBRARIES}) - include_directories(${Zstd_INCLUDE_DIRS}) - endif() -endif() - #libpsl option(CURL_USE_LIBPSL "Use libPSL" ON) mark_as_advanced(CURL_USE_LIBPSL) @@ -1035,7 +1059,9 @@ elseif("${CURL_CA_BUNDLE}" STREQUAL "none") unset(CURL_CA_BUNDLE CACHE) elseif("${CURL_CA_BUNDLE}" STREQUAL "auto") unset(CURL_CA_BUNDLE CACHE) - set(CURL_CA_BUNDLE_AUTODETECT TRUE) + if(NOT CMAKE_CROSSCOMPILING) + set(CURL_CA_BUNDLE_AUTODETECT TRUE) + endif() else() set(CURL_CA_BUNDLE_SET TRUE) endif() @@ -1046,7 +1072,7 @@ elseif("${CURL_CA_PATH}" STREQUAL "none") unset(CURL_CA_PATH CACHE) elseif("${CURL_CA_PATH}" STREQUAL "auto") unset(CURL_CA_PATH CACHE) - if(NOT USE_NSS) + if(NOT CMAKE_CROSSCOMPILING AND NOT USE_NSS) set(CURL_CA_PATH_AUTODETECT TRUE) endif() else() @@ -1156,7 +1182,6 @@ check_include_file_concat("unistd.h" HAVE_UNISTD_H) check_include_file_concat("utime.h" HAVE_UTIME_H) check_include_file_concat("stddef.h" HAVE_STDDEF_H) -check_include_file_concat("stdint.h" HAVE_STDINT_H) check_include_file_concat("sys/utsname.h" HAVE_SYS_UTSNAME_H) check_type_size(size_t SIZEOF_SIZE_T) @@ -1208,7 +1233,6 @@ check_symbol_exists(gethostbyname_r "${CURL_INCLUDES}" HAVE_GETHOSTBYNAME_R) check_symbol_exists(signal "${CURL_INCLUDES}" HAVE_SIGNAL) check_symbol_exists(strtoll "${CURL_INCLUDES}" HAVE_STRTOLL) -check_symbol_exists(_strtoi64 "${CURL_INCLUDES}" HAVE__STRTOI64) check_symbol_exists(strerror_r "${CURL_INCLUDES}" HAVE_STRERROR_R) check_symbol_exists(siginterrupt "${CURL_INCLUDES}" HAVE_SIGINTERRUPT) check_symbol_exists(getaddrinfo "${CURL_INCLUDES}" HAVE_GETADDRINFO) @@ -1415,8 +1439,6 @@ else() set(CURL_PULL_SYS_SOCKET_H ${HAVE_SYS_SOCKET_H}) set(CURL_PULL_SYS_POLL_H ${HAVE_SYS_POLL_H}) endif() -set(CURL_PULL_STDINT_H ${HAVE_STDINT_H}) -set(CURL_PULL_INTTYPES_H ${HAVE_INTTYPES_H}) include(CMake/OtherTests.cmake) diff --git a/Utilities/cmcurl/include/curl/curl.h b/Utilities/cmcurl/include/curl/curl.h index c5ce0a5..4c6288d 100644 --- a/Utilities/cmcurl/include/curl/curl.h +++ b/Utilities/cmcurl/include/curl/curl.h @@ -34,11 +34,12 @@ #endif /* Compile-time deprecation macros. */ -#if defined(__GNUC__) && (__GNUC__ >= 6) && \ +#if defined(__GNUC__) && \ + ((__GNUC__ > 12) || ((__GNUC__ == 12) && (__GNUC_MINOR__ >= 1 ))) && \ !defined(__INTEL_COMPILER) && \ !defined(CURL_DISABLE_DEPRECATION) && !defined(BUILDING_LIBCURL) -#define CURL_DEPRECATED(version, message) \ - __attribute__((deprecated("since " # version ". " message))) +#define CURL_DEPRECATED(version, message) \ + __attribute__((deprecated("since " # version ". " message))) #define CURL_IGNORE_DEPRECATION(statements) \ _Pragma("GCC diagnostic push") \ _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") \ diff --git a/Utilities/cmcurl/include/curl/curlver.h b/Utilities/cmcurl/include/curl/curlver.h index ce39cdc..6f2affa 100644 --- a/Utilities/cmcurl/include/curl/curlver.h +++ b/Utilities/cmcurl/include/curl/curlver.h @@ -32,12 +32,12 @@ /* This is the version number of the libcurl package from which this header file origins: */ -#define LIBCURL_VERSION "7.88.1" +#define LIBCURL_VERSION "8.0.1" /* The numeric version number is also available "in parts" by using these defines: */ -#define LIBCURL_VERSION_MAJOR 7 -#define LIBCURL_VERSION_MINOR 88 +#define LIBCURL_VERSION_MAJOR 8 +#define LIBCURL_VERSION_MINOR 0 #define LIBCURL_VERSION_PATCH 1 /* This is the numeric version of the libcurl version number, meant for easier @@ -59,7 +59,7 @@ CURL_VERSION_BITS() macro since curl's own configure script greps for it and needs it to contain the full number. */ -#define LIBCURL_VERSION_NUM 0x075801 +#define LIBCURL_VERSION_NUM 0x080001 /* * This is the date and time when the full source package was created. The diff --git a/Utilities/cmcurl/include/curl/urlapi.h b/Utilities/cmcurl/include/curl/urlapi.h index b97b534..b3504b6 100644 --- a/Utilities/cmcurl/include/curl/urlapi.h +++ b/Utilities/cmcurl/include/curl/urlapi.h @@ -117,14 +117,14 @@ CURL_EXTERN void curl_url_cleanup(CURLU *handle); * curl_url_dup() duplicates a CURLU handle and returns a new copy. The new * handle must also be freed with curl_url_cleanup(). */ -CURL_EXTERN CURLU *curl_url_dup(CURLU *in); +CURL_EXTERN CURLU *curl_url_dup(const CURLU *in); /* * curl_url_get() extracts a specific part of the URL from a CURLU * handle. Returns error code. The returned pointer MUST be freed with * curl_free() afterwards. */ -CURL_EXTERN CURLUcode curl_url_get(CURLU *handle, CURLUPart what, +CURL_EXTERN CURLUcode curl_url_get(const CURLU *handle, CURLUPart what, char **part, unsigned int flags); /* diff --git a/Utilities/cmcurl/lib/CMakeLists.txt b/Utilities/cmcurl/lib/CMakeLists.txt index 15853ff..c3eb842 100644 --- a/Utilities/cmcurl/lib/CMakeLists.txt +++ b/Utilities/cmcurl/lib/CMakeLists.txt @@ -47,29 +47,6 @@ if(WIN32 AND NOT CURL_STATICLIB) list(APPEND CSOURCES libcurl.rc) endif() -# SET(CSOURCES -# # memdebug.c -not used -# # nwlib.c - Not used -# # strtok.c - specify later -# # strtoofft.c - specify later -# ) - -# #OPTION(CURL_MALLOC_DEBUG "Debug mallocs in Curl" OFF) -# MARK_AS_ADVANCED(CURL_MALLOC_DEBUG) -# IF(CURL_MALLOC_DEBUG) -# SET(CSOURCES ${CSOURCES} -# memdebug.c -# ) -# ENDIF(CURL_MALLOC_DEBUG) - -# # only build compat strtoofft if we need to -# IF(NOT HAVE_STRTOLL AND NOT HAVE__STRTOI64) -# SET(CSOURCES ${CSOURCES} -# strtoofft.c -# ) -# ENDIF(NOT HAVE_STRTOLL AND NOT HAVE__STRTOI64) - - # The rest of the build include_directories(${CMAKE_CURRENT_BINARY_DIR}/../include) diff --git a/Utilities/cmcurl/lib/Makefile.inc b/Utilities/cmcurl/lib/Makefile.inc index c28b475..663190a 100644 --- a/Utilities/cmcurl/lib/Makefile.inc +++ b/Utilities/cmcurl/lib/Makefile.inc @@ -107,7 +107,7 @@ LIB_CFILES = \ base64.c \ bufref.c \ c-hyper.c \ - cf-http.c \ + cf-https-connect.c \ cf-socket.c \ cfilters.c \ conncache.c \ @@ -223,7 +223,6 @@ LIB_CFILES = \ version.c \ version_win32.c \ warnless.c \ - wildcard.c \ ws.c LIB_HFILES = \ @@ -233,7 +232,7 @@ LIB_HFILES = \ asyn.h \ bufref.h \ c-hyper.h \ - cf-http.h \ + cf-https-connect.h \ cf-socket.h \ cfilters.h \ conncache.h \ @@ -352,7 +351,6 @@ LIB_HFILES = \ urldata.h \ version_win32.h \ warnless.h \ - wildcard.h \ ws.h LIB_RCFILES = libcurl.rc diff --git a/Utilities/cmcurl/lib/cf-http.c b/Utilities/cmcurl/lib/cf-https-connect.c index 2ee3d4d..ed70ad0 100644 --- a/Utilities/cmcurl/lib/cf-http.c +++ b/Utilities/cmcurl/lib/cf-https-connect.c @@ -32,7 +32,7 @@ #include "cfilters.h" #include "connect.h" #include "multiif.h" -#include "cf-http.h" +#include "cf-https-connect.h" #include "http2.h" #include "vquic/vquic.h" @@ -266,7 +266,8 @@ static CURLcode cf_hc_connect(struct Curl_cfilter *cf, Curl_expire(data, ctx->soft_eyeballs_timeout_ms, EXPIRE_ALPN_EYEBALLS); } else if(ctx->h21_baller.enabled) - cf_hc_baller_init(&ctx->h21_baller, cf, data, "h21", TRNSPRT_TCP); + cf_hc_baller_init(&ctx->h21_baller, cf, data, "h21", + cf->conn->transport); ctx->state = CF_HC_CONNECT; /* FALLTHROUGH */ @@ -280,7 +281,8 @@ static CURLcode cf_hc_connect(struct Curl_cfilter *cf, } if(time_to_start_h21(cf, data, now)) { - cf_hc_baller_init(&ctx->h21_baller, cf, data, "h21", TRNSPRT_TCP); + cf_hc_baller_init(&ctx->h21_baller, cf, data, "h21", + cf->conn->transport); } if(cf_hc_baller_is_active(&ctx->h21_baller)) { @@ -374,6 +376,55 @@ static bool cf_hc_data_pending(struct Curl_cfilter *cf, || cf_hc_baller_data_pending(&ctx->h21_baller, data); } +static struct curltime get_max_baller_time(struct Curl_cfilter *cf, + struct Curl_easy *data, + int query) +{ + struct cf_hc_ctx *ctx = cf->ctx; + struct Curl_cfilter *cfb; + struct curltime t, tmax; + + memset(&tmax, 0, sizeof(tmax)); + memset(&t, 0, sizeof(t)); + cfb = ctx->h21_baller.enabled? ctx->h21_baller.cf : NULL; + if(cfb && !cfb->cft->query(cfb, data, query, NULL, &t)) { + if((t.tv_sec || t.tv_usec) && Curl_timediff_us(t, tmax) > 0) + tmax = t; + } + memset(&t, 0, sizeof(t)); + cfb = ctx->h3_baller.enabled? ctx->h3_baller.cf : NULL; + if(cfb && !cfb->cft->query(cfb, data, query, NULL, &t)) { + if((t.tv_sec || t.tv_usec) && Curl_timediff_us(t, tmax) > 0) + tmax = t; + } + return tmax; +} + +static CURLcode cf_hc_query(struct Curl_cfilter *cf, + struct Curl_easy *data, + int query, int *pres1, void *pres2) +{ + if(!cf->connected) { + switch(query) { + case CF_QUERY_TIMER_CONNECT: { + struct curltime *when = pres2; + *when = get_max_baller_time(cf, data, CF_QUERY_TIMER_CONNECT); + return CURLE_OK; + } + case CF_QUERY_TIMER_APPCONNECT: { + struct curltime *when = pres2; + *when = get_max_baller_time(cf, data, CF_QUERY_TIMER_APPCONNECT); + return CURLE_OK; + } + default: + break; + } + } + return cf->next? + cf->next->cft->query(cf->next, data, query, pres1, pres2) : + CURLE_UNKNOWN_OPTION; +} + static void cf_hc_close(struct Curl_cfilter *cf, struct Curl_easy *data) { DEBUGF(LOG_CF(data, cf, "close")); @@ -411,7 +462,7 @@ struct Curl_cftype Curl_cft_http_connect = { Curl_cf_def_cntrl, Curl_cf_def_conn_is_alive, Curl_cf_def_conn_keep_alive, - Curl_cf_def_query, + cf_hc_query, }; static CURLcode cf_hc_create(struct Curl_cfilter **pcf, diff --git a/Utilities/cmcurl/lib/cf-http.h b/Utilities/cmcurl/lib/cf-https-connect.h index 6a39527..6a39527 100644 --- a/Utilities/cmcurl/lib/cf-http.h +++ b/Utilities/cmcurl/lib/cf-https-connect.h diff --git a/Utilities/cmcurl/lib/cf-socket.c b/Utilities/cmcurl/lib/cf-socket.c index 2549f34..6d9ace4 100644 --- a/Utilities/cmcurl/lib/cf-socket.c +++ b/Utilities/cmcurl/lib/cf-socket.c @@ -253,19 +253,6 @@ static CURLcode socket_open(struct Curl_easy *data, else { /* opensocket callback not set, so simply create the socket now */ *sockfd = socket(addr->family, addr->socktype, addr->protocol); - if(!*sockfd && addr->socktype == SOCK_DGRAM) { - /* This is icky and seems, at least, to happen on macOS: - * we get sockfd == 0 and if called again, we get a valid one > 0. - * If we close the 0, we sometimes get failures in multi poll, as - * 0 seems also be the fd for the sockpair used for WAKEUP polling. - * Very strange. Maybe this code should be ifdef'ed for macOS, but - * on "real" OS, fd 0 is stdin and we never see that. So... - */ - fake_sclose(*sockfd); - *sockfd = socket(addr->family, addr->socktype, addr->protocol); - DEBUGF(infof(data, "QUIRK: UDP socket() gave handle 0, 2nd attempt %d", - (int)*sockfd)); - } } if(*sockfd == CURL_SOCKET_BAD) @@ -338,20 +325,6 @@ int Curl_socket_close(struct Curl_easy *data, struct connectdata *conn, return socket_close(data, conn, FALSE, sock); } -bool Curl_socket_is_dead(curl_socket_t sock) -{ - int sval; - bool ret_val = TRUE; - - sval = SOCKET_READABLE(sock, 0); - if(sval == 0) - /* timeout */ - ret_val = FALSE; - - return ret_val; -} - - #ifdef USE_WINSOCK /* When you run a program that uses the Windows Sockets API, you may experience slow performance when you copy data to a TCP server. @@ -522,7 +495,7 @@ static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn, conn->ip_version = CURL_IPRESOLVE_V6; #endif - rc = Curl_resolv(data, dev, 0, FALSE, &h); + rc = Curl_resolv(data, dev, 80, FALSE, &h); if(rc == CURLRESOLV_PENDING) (void)Curl_resolver_wait_resolv(data, &h); conn->ip_version = ipver; @@ -1084,6 +1057,11 @@ static CURLcode cf_tcp_connect(struct Curl_cfilter *cf, if(result) goto out; + if(cf->connected) { + *done = TRUE; + return CURLE_OK; + } + /* Connect TCP socket */ rc = do_connect(cf, data, cf->conn->bits.tcp_fastopen); if(-1 == rc) { @@ -1449,22 +1427,6 @@ static CURLcode cf_socket_cntrl(struct Curl_cfilter *cf, case CF_CTRL_CONN_INFO_UPDATE: cf_socket_active(cf, data); break; - case CF_CTRL_CONN_REPORT_STATS: - switch(ctx->transport) { - case TRNSPRT_UDP: - case TRNSPRT_QUIC: - /* Since UDP connected sockets work different from TCP, we use the - * time of the first byte from the peer as the "connect" time. */ - if(ctx->got_first_byte) { - Curl_pgrsTimeWas(data, TIMER_CONNECT, ctx->first_byte_at); - break; - } - /* FALLTHROUGH */ - default: - Curl_pgrsTimeWas(data, TIMER_CONNECT, ctx->connected_at); - break; - } - break; case CF_CTRL_DATA_SETUP: Curl_persistconninfo(data, cf->conn, ctx->l_ip, ctx->l_port); break; @@ -1473,38 +1435,39 @@ static CURLcode cf_socket_cntrl(struct Curl_cfilter *cf, } static bool cf_socket_conn_is_alive(struct Curl_cfilter *cf, - struct Curl_easy *data) + struct Curl_easy *data, + bool *input_pending) { struct cf_socket_ctx *ctx = cf->ctx; - int sval; + struct pollfd pfd[1]; + int r; + *input_pending = FALSE; (void)data; if(!ctx || ctx->sock == CURL_SOCKET_BAD) return FALSE; - sval = SOCKET_READABLE(ctx->sock, 0); - if(sval == 0) { - /* timeout */ - return TRUE; - } - else if(sval & CURL_CSELECT_ERR) { - /* socket is in an error state */ + /* Check with 0 timeout if there are any events pending on the socket */ + pfd[0].fd = ctx->sock; + pfd[0].events = POLLRDNORM|POLLIN|POLLRDBAND|POLLPRI; + pfd[0].revents = 0; + + r = Curl_poll(pfd, 1, 0); + if(r < 0) { + DEBUGF(LOG_CF(data, cf, "is_alive: poll error, assume dead")); return FALSE; } - else if(sval & CURL_CSELECT_IN) { - /* readable with no error. could still be closed */ -/* Minix 3.1 doesn't support any flags on recv; just assume socket is OK */ -#ifdef MSG_PEEK - /* use the socket */ - char buf; - if(recv((RECV_TYPE_ARG1)ctx->sock, (RECV_TYPE_ARG2)&buf, - (RECV_TYPE_ARG3)1, (RECV_TYPE_ARG4)MSG_PEEK) == 0) { - return FALSE; /* FIN received */ - } -#endif + else if(r == 0) { + DEBUGF(LOG_CF(data, cf, "is_alive: poll timeout, assume alive")); return TRUE; } + else if(pfd[0].revents & (POLLERR|POLLHUP|POLLPRI|POLLNVAL)) { + DEBUGF(LOG_CF(data, cf, "is_alive: err/hup/etc events, assume dead")); + return FALSE; + } + DEBUGF(LOG_CF(data, cf, "is_alive: valid events, looks alive")); + *input_pending = TRUE; return TRUE; } @@ -1527,6 +1490,24 @@ static CURLcode cf_socket_query(struct Curl_cfilter *cf, else *pres1 = -1; return CURLE_OK; + case CF_QUERY_TIMER_CONNECT: { + struct curltime *when = pres2; + switch(ctx->transport) { + case TRNSPRT_UDP: + case TRNSPRT_QUIC: + /* Since UDP connected sockets work different from TCP, we use the + * time of the first byte from the peer as the "connect" time. */ + if(ctx->got_first_byte) { + *when = ctx->first_byte_at; + break; + } + /* FALLTHROUGH */ + default: + *when = ctx->connected_at; + break; + } + return CURLE_OK; + } default: break; } @@ -1826,7 +1807,6 @@ CURLcode Curl_conn_tcp_listen_set(struct Curl_easy *data, Curl_conn_cf_add(data, conn, sockindex, cf); conn->sock[sockindex] = ctx->sock; - set_remote_ip(cf, data); set_local_ip(cf, data); ctx->active = TRUE; ctx->connected_at = Curl_now(); @@ -1841,6 +1821,38 @@ out: return result; } +static void set_accepted_remote_ip(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + struct cf_socket_ctx *ctx = cf->ctx; +#ifdef HAVE_GETPEERNAME + char buffer[STRERROR_LEN]; + struct Curl_sockaddr_storage ssrem; + curl_socklen_t plen; + + ctx->r_ip[0] = 0; + ctx->r_port = 0; + plen = sizeof(ssrem); + memset(&ssrem, 0, plen); + if(getpeername(ctx->sock, (struct sockaddr*) &ssrem, &plen)) { + int error = SOCKERRNO; + failf(data, "getpeername() failed with errno %d: %s", + error, Curl_strerror(error, buffer, sizeof(buffer))); + return; + } + if(!Curl_addr2string((struct sockaddr*)&ssrem, plen, + ctx->r_ip, &ctx->r_port)) { + failf(data, "ssrem inet_ntop() failed with errno %d: %s", + errno, Curl_strerror(errno, buffer, sizeof(buffer))); + return; + } +#else + ctx->r_ip[0] = 0; + ctx->r_port = 0; + (void)data; +#endif +} + CURLcode Curl_conn_tcp_accepted_set(struct Curl_easy *data, struct connectdata *conn, int sockindex, curl_socket_t *s) @@ -1857,13 +1869,14 @@ CURLcode Curl_conn_tcp_accepted_set(struct Curl_easy *data, socket_close(data, conn, TRUE, ctx->sock); ctx->sock = *s; conn->sock[sockindex] = ctx->sock; - set_remote_ip(cf, data); + set_accepted_remote_ip(cf, data); set_local_ip(cf, data); ctx->active = TRUE; ctx->accepted = TRUE; ctx->connected_at = Curl_now(); cf->connected = TRUE; - DEBUGF(LOG_CF(data, cf, "Curl_conn_tcp_accepted_set(%d)", (int)ctx->sock)); + DEBUGF(LOG_CF(data, cf, "accepted_set(sock=%d, remote=%s port=%d)", + (int)ctx->sock, ctx->r_ip, ctx->r_port)); return CURLE_OK; } diff --git a/Utilities/cmcurl/lib/cf-socket.h b/Utilities/cmcurl/lib/cf-socket.h index f6eb810..0eec61a 100644 --- a/Utilities/cmcurl/lib/cf-socket.h +++ b/Utilities/cmcurl/lib/cf-socket.h @@ -70,13 +70,6 @@ CURLcode Curl_socket_open(struct Curl_easy *data, int Curl_socket_close(struct Curl_easy *data, struct connectdata *conn, curl_socket_t sock); -/* - * This function should return TRUE if the socket is to be assumed to - * be dead. Most commonly this happens when the server has closed the - * connection due to inactivity. - */ -bool Curl_socket_is_dead(curl_socket_t sock); - /** * Determine the curl code for a socket connect() == -1 with errno. */ diff --git a/Utilities/cmcurl/lib/cfilters.c b/Utilities/cmcurl/lib/cfilters.c index 2af0dd8..e60d138 100644 --- a/Utilities/cmcurl/lib/cfilters.c +++ b/Utilities/cmcurl/lib/cfilters.c @@ -124,10 +124,11 @@ ssize_t Curl_cf_def_recv(struct Curl_cfilter *cf, struct Curl_easy *data, } bool Curl_cf_def_conn_is_alive(struct Curl_cfilter *cf, - struct Curl_easy *data) + struct Curl_easy *data, + bool *input_pending) { return cf->next? - cf->next->cft->is_alive(cf->next, data) : + cf->next->cft->is_alive(cf->next, data, input_pending) : FALSE; /* pessimistic in absence of data */ } @@ -370,9 +371,12 @@ CURLcode Curl_conn_connect(struct Curl_easy *data, result = cf->cft->connect(cf, data, blocking, done); if(!result && *done) { Curl_conn_ev_update_info(data, data->conn); - Curl_conn_ev_report_stats(data, data->conn); + Curl_conn_report_connect_stats(data, data->conn); data->conn->keepalive = Curl_now(); } + else if(result) { + Curl_conn_report_connect_stats(data, data->conn); + } } return result; @@ -608,16 +612,32 @@ void Curl_conn_ev_update_info(struct Curl_easy *data, cf_cntrl_all(conn, data, TRUE, CF_CTRL_CONN_INFO_UPDATE, 0, NULL); } -void Curl_conn_ev_report_stats(struct Curl_easy *data, - struct connectdata *conn) +void Curl_conn_report_connect_stats(struct Curl_easy *data, + struct connectdata *conn) { - cf_cntrl_all(conn, data, TRUE, CF_CTRL_CONN_REPORT_STATS, 0, NULL); + struct Curl_cfilter *cf = conn->cfilter[FIRSTSOCKET]; + if(cf) { + struct curltime connected; + struct curltime appconnected; + + memset(&connected, 0, sizeof(connected)); + cf->cft->query(cf, data, CF_QUERY_TIMER_CONNECT, NULL, &connected); + if(connected.tv_sec || connected.tv_usec) + Curl_pgrsTimeWas(data, TIMER_CONNECT, connected); + + memset(&appconnected, 0, sizeof(appconnected)); + cf->cft->query(cf, data, CF_QUERY_TIMER_APPCONNECT, NULL, &appconnected); + if(appconnected.tv_sec || appconnected.tv_usec) + Curl_pgrsTimeWas(data, TIMER_APPCONNECT, appconnected); + } } -bool Curl_conn_is_alive(struct Curl_easy *data, struct connectdata *conn) +bool Curl_conn_is_alive(struct Curl_easy *data, struct connectdata *conn, + bool *input_pending) { struct Curl_cfilter *cf = conn->cfilter[FIRSTSOCKET]; - return cf && !cf->conn->bits.close && cf->cft->is_alive(cf, data); + return cf && !cf->conn->bits.close && + cf->cft->is_alive(cf, data, input_pending); } CURLcode Curl_conn_keep_alive(struct Curl_easy *data, diff --git a/Utilities/cmcurl/lib/cfilters.h b/Utilities/cmcurl/lib/cfilters.h index 94dc53f..317f2bb 100644 --- a/Utilities/cmcurl/lib/cfilters.h +++ b/Utilities/cmcurl/lib/cfilters.h @@ -85,7 +85,8 @@ typedef ssize_t Curl_cft_recv(struct Curl_cfilter *cf, CURLcode *err); /* error to return */ typedef bool Curl_cft_conn_is_alive(struct Curl_cfilter *cf, - struct Curl_easy *data); + struct Curl_easy *data, + bool *input_pending); typedef CURLcode Curl_cft_conn_keep_alive(struct Curl_cfilter *cf, struct Curl_easy *data); @@ -109,8 +110,6 @@ typedef CURLcode Curl_cft_conn_keep_alive(struct Curl_cfilter *cf, #define CF_CTRL_DATA_DONE_SEND 8 /* 0 NULL ignored */ /* update conn info at connection and data */ #define CF_CTRL_CONN_INFO_UPDATE (256+0) /* 0 NULL ignored */ -/* report conn statistics (timers) for connection and data */ -#define CF_CTRL_CONN_REPORT_STATS (256+1) /* 0 NULL ignored */ /** * Handle event/control for the filter. @@ -138,6 +137,8 @@ typedef CURLcode Curl_cft_cntrl(struct Curl_cfilter *cf, #define CF_QUERY_MAX_CONCURRENT 1 /* number - */ #define CF_QUERY_CONNECT_REPLY_MS 2 /* number - */ #define CF_QUERY_SOCKET 3 /* - curl_socket_t */ +#define CF_QUERY_TIMER_CONNECT 4 /* - struct curltime */ +#define CF_QUERY_TIMER_APPCONNECT 5 /* - struct curltime */ /** * Query the cfilter for properties. Filters ignorant of a query will @@ -216,7 +217,8 @@ CURLcode Curl_cf_def_cntrl(struct Curl_cfilter *cf, struct Curl_easy *data, int event, int arg1, void *arg2); bool Curl_cf_def_conn_is_alive(struct Curl_cfilter *cf, - struct Curl_easy *data); + struct Curl_easy *data, + bool *input_pending); CURLcode Curl_cf_def_conn_keep_alive(struct Curl_cfilter *cf, struct Curl_easy *data); CURLcode Curl_cf_def_query(struct Curl_cfilter *cf, @@ -435,15 +437,16 @@ void Curl_conn_ev_update_info(struct Curl_easy *data, struct connectdata *conn); /** - * Inform connection filters to report statistics. + * Update connection statistics */ -void Curl_conn_ev_report_stats(struct Curl_easy *data, - struct connectdata *conn); +void Curl_conn_report_connect_stats(struct Curl_easy *data, + struct connectdata *conn); /** * Check if FIRSTSOCKET's cfilter chain deems connection alive. */ -bool Curl_conn_is_alive(struct Curl_easy *data, struct connectdata *conn); +bool Curl_conn_is_alive(struct Curl_easy *data, struct connectdata *conn, + bool *input_pending); /** * Try to upkeep the connection filters at sockindex. diff --git a/Utilities/cmcurl/lib/conncache.c b/Utilities/cmcurl/lib/conncache.c index c21b96c..1c736da 100644 --- a/Utilities/cmcurl/lib/conncache.c +++ b/Utilities/cmcurl/lib/conncache.c @@ -45,13 +45,6 @@ #define HASHKEY_SIZE 128 -static void conn_llist_dtor(void *user, void *element) -{ - struct connectdata *conn = element; - (void)user; - conn->bundle = NULL; -} - static CURLcode bundle_create(struct connectbundle **bundlep) { DEBUGASSERT(*bundlep == NULL); @@ -62,17 +55,12 @@ static CURLcode bundle_create(struct connectbundle **bundlep) (*bundlep)->num_connections = 0; (*bundlep)->multiuse = BUNDLE_UNKNOWN; - Curl_llist_init(&(*bundlep)->conn_list, (Curl_llist_dtor) conn_llist_dtor); + Curl_llist_init(&(*bundlep)->conn_list, NULL); return CURLE_OK; } static void bundle_destroy(struct connectbundle *bundle) { - if(!bundle) - return; - - Curl_llist_destroy(&bundle->conn_list, NULL); - free(bundle); } diff --git a/Utilities/cmcurl/lib/connect.c b/Utilities/cmcurl/lib/connect.c index 993a7f9..10d0c11 100644 --- a/Utilities/cmcurl/lib/connect.c +++ b/Utilities/cmcurl/lib/connect.c @@ -59,7 +59,7 @@ #include "strerror.h" #include "cfilters.h" #include "connect.h" -#include "cf-http.h" +#include "cf-https-connect.h" #include "cf-socket.h" #include "select.h" #include "url.h" /* for Curl_safefree() */ @@ -957,6 +957,28 @@ static bool cf_he_data_pending(struct Curl_cfilter *cf, return FALSE; } +static struct curltime get_max_baller_time(struct Curl_cfilter *cf, + struct Curl_easy *data, + int query) +{ + struct cf_he_ctx *ctx = cf->ctx; + struct curltime t, tmax; + size_t i; + + memset(&tmax, 0, sizeof(tmax)); + for(i = 0; i < sizeof(ctx->baller)/sizeof(ctx->baller[0]); i++) { + struct eyeballer *baller = ctx->baller[i]; + + memset(&t, 0, sizeof(t)); + if(baller && baller->cf && + !baller->cf->cft->query(baller->cf, data, query, NULL, &t)) { + if((t.tv_sec || t.tv_usec) && Curl_timediff_us(t, tmax) > 0) + tmax = t; + } + } + return tmax; +} + static CURLcode cf_he_query(struct Curl_cfilter *cf, struct Curl_easy *data, int query, int *pres1, void *pres2) @@ -984,7 +1006,16 @@ static CURLcode cf_he_query(struct Curl_cfilter *cf, DEBUGF(LOG_CF(data, cf, "query connect reply: %dms", *pres1)); return CURLE_OK; } - + case CF_QUERY_TIMER_CONNECT: { + struct curltime *when = pres2; + *when = get_max_baller_time(cf, data, CF_QUERY_TIMER_CONNECT); + return CURLE_OK; + } + case CF_QUERY_TIMER_APPCONNECT: { + struct curltime *when = pres2; + *when = get_max_baller_time(cf, data, CF_QUERY_TIMER_APPCONNECT); + return CURLE_OK; + } default: break; } diff --git a/Utilities/cmcurl/lib/content_encoding.c b/Utilities/cmcurl/lib/content_encoding.c index a29d204..aa1e0cb 100644 --- a/Utilities/cmcurl/lib/content_encoding.c +++ b/Utilities/cmcurl/lib/content_encoding.c @@ -33,7 +33,15 @@ #endif #ifdef HAVE_BROTLI +#if defined(__GNUC__) +/* Ignore -Wvla warnings in brotli headers */ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wvla" +#endif #include <brotli/decode.h> +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif #endif #ifdef HAVE_ZSTD diff --git a/Utilities/cmcurl/lib/cookie.c b/Utilities/cmcurl/lib/cookie.c index c457b2d..0c6e0f7 100644 --- a/Utilities/cmcurl/lib/cookie.c +++ b/Utilities/cmcurl/lib/cookie.c @@ -101,13 +101,14 @@ Example set of cookies: #include "parsedate.h" #include "rename.h" #include "fopen.h" +#include "strdup.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" -static void strstore(char **str, const char *newstr); +static void strstore(char **str, const char *newstr, size_t len); static void freecookie(struct Cookie *co) { @@ -122,15 +123,17 @@ static void freecookie(struct Cookie *co) free(co); } -static bool tailmatch(const char *cooke_domain, const char *hostname) +static bool tailmatch(const char *cookie_domain, size_t cookie_domain_len, + const char *hostname) { - size_t cookie_domain_len = strlen(cooke_domain); size_t hostname_len = strlen(hostname); if(hostname_len < cookie_domain_len) return FALSE; - if(!strcasecompare(cooke_domain, hostname + hostname_len-cookie_domain_len)) + if(!strncasecompare(cookie_domain, + hostname + hostname_len-cookie_domain_len, + cookie_domain_len)) return FALSE; /* @@ -176,7 +179,7 @@ static bool pathmatch(const char *cookie_path, const char *request_uri) /* #-fragments are already cut off! */ if(0 == strlen(uri_path) || uri_path[0] != '/') { - strstore(&uri_path, "/"); + strstore(&uri_path, "/", 1); if(!uri_path) return FALSE; } @@ -310,7 +313,7 @@ static char *sanitize_cookie_path(const char *cookie_path) /* RFC6265 5.2.4 The Path Attribute */ if(new_path[0] != '/') { /* Let cookie-path be the default-path. */ - strstore(&new_path, "/"); + strstore(&new_path, "/", 1); return new_path; } @@ -333,10 +336,9 @@ void Curl_cookie_loadfiles(struct Curl_easy *data) if(list) { Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); while(list) { - struct CookieInfo *newcookies = Curl_cookie_init(data, - list->data, - data->cookies, - data->set.cookiesession); + struct CookieInfo *newcookies = + Curl_cookie_init(data, list->data, data->cookies, + data->set.cookiesession); if(!newcookies) /* * Failure may be due to OOM or a bad cookie; both are ignored @@ -360,10 +362,14 @@ void Curl_cookie_loadfiles(struct Curl_easy *data) * parsing in a last-wins scenario. The caller is responsible for checking * for OOM errors. */ -static void strstore(char **str, const char *newstr) +static void strstore(char **str, const char *newstr, size_t len) { + DEBUGASSERT(newstr); + DEBUGASSERT(str); free(*str); - *str = strdup(newstr); + *str = Curl_memdup(newstr, len + 1); + if(*str) + (*str)[len] = 0; } /* @@ -425,15 +431,19 @@ static void remove_expired(struct CookieInfo *cookies) } /* Make sure domain contains a dot or is localhost. */ -static bool bad_domain(const char *domain) +static bool bad_domain(const char *domain, size_t len) { - if(strcasecompare(domain, "localhost")) + if((len == 9) && strncasecompare(domain, "localhost", 9)) return FALSE; else { /* there must be a dot present, but that dot must not be a trailing dot */ - char *dot = strchr(domain, '.'); - if(dot) - return dot[1] ? FALSE : TRUE; + char *dot = memchr(domain, '.', len); + if(dot) { + size_t i = dot - domain; + if((len - i) > 1) + /* the dot is not the last byte */ + return FALSE; + } } return TRUE; } @@ -513,10 +523,9 @@ Curl_cookie_add(struct Curl_easy *data, if(httpheader) { /* This line was read off an HTTP-header */ - char name[MAX_NAME]; - char what[MAX_NAME]; + const char *namep; + const char *valuep; const char *ptr; - const char *semiptr; size_t linelength = strlen(lineptr); if(linelength > MAX_COOKIE_LINE) { @@ -525,73 +534,65 @@ Curl_cookie_add(struct Curl_easy *data, return NULL; } - semiptr = strchr(lineptr, ';'); /* first, find a semicolon */ - - while(*lineptr && ISBLANK(*lineptr)) - lineptr++; - ptr = lineptr; do { - /* we have a <what>=<this> pair or a stand-alone word here */ - name[0] = what[0] = 0; /* init the buffers */ - if(1 <= sscanf(ptr, "%" MAX_NAME_TXT "[^;\t\r\n=] =%" - MAX_NAME_TXT "[^;\r\n]", - name, what)) { - /* - * Use strstore() below to properly deal with received cookie - * headers that have the same string property set more than once, - * and then we use the last one. - */ - const char *whatptr; + size_t vlen; + size_t nlen; + + while(*ptr && ISBLANK(*ptr)) + ptr++; + + /* we have a <name>=<value> pair or a stand-alone word here */ + nlen = strcspn(ptr, ";\t\r\n="); + if(nlen) { bool done = FALSE; - bool sep; - size_t len = strlen(what); - size_t nlen = strlen(name); - const char *endofn = &ptr[ nlen ]; + bool sep = FALSE; - /* - * Check for too long individual name or contents, or too long - * combination of name + contents. Chrome and Firefox support 4095 or - * 4096 bytes combo - */ - if(nlen >= (MAX_NAME-1) || len >= (MAX_NAME-1) || - ((nlen + len) > MAX_NAME)) { - freecookie(co); - infof(data, "oversized cookie dropped, name/val %zu + %zu bytes", - nlen, len); - return NULL; - } + namep = ptr; + ptr += nlen; - /* name ends with a '=' ? */ - sep = (*endofn == '=')?TRUE:FALSE; + /* trim trailing spaces and tabs after name */ + while(nlen && ISBLANK(namep[nlen - 1])) + nlen--; - if(nlen) { - endofn--; /* move to the last character */ - if(ISBLANK(*endofn)) { - /* skip trailing spaces in name */ - while(*endofn && ISBLANK(*endofn) && nlen) { - endofn--; - nlen--; - } - name[nlen] = 0; /* new end of name */ + if(*ptr == '=') { + vlen = strcspn(++ptr, ";\r\n"); + valuep = ptr; + sep = TRUE; + ptr = &valuep[vlen]; + + /* Strip off trailing whitespace from the value */ + while(vlen && ISBLANK(valuep[vlen-1])) + vlen--; + + /* Skip leading whitespace from the value */ + while(vlen && ISBLANK(*valuep)) { + valuep++; + vlen--; } - } - /* Strip off trailing whitespace from the 'what' */ - while(len && ISBLANK(what[len-1])) { - what[len-1] = 0; - len--; + /* Reject cookies with a TAB inside the value */ + if(memchr(valuep, '\t', vlen)) { + freecookie(co); + infof(data, "cookie contains TAB, dropping"); + return NULL; + } + } + else { + valuep = NULL; + vlen = 0; } - /* Skip leading whitespace from the 'what' */ - whatptr = what; - while(*whatptr && ISBLANK(*whatptr)) - whatptr++; - - /* Reject cookies with a TAB inside the content */ - if(strchr(whatptr, '\t')) { + /* + * Check for too long individual name or contents, or too long + * combination of name + contents. Chrome and Firefox support 4095 or + * 4096 bytes combo + */ + if(nlen >= (MAX_NAME-1) || vlen >= (MAX_NAME-1) || + ((nlen + vlen) > MAX_NAME)) { freecookie(co); - infof(data, "cookie contains TAB, dropping"); + infof(data, "oversized cookie dropped, name/val %zu + %zu bytes", + nlen, vlen); return NULL; } @@ -601,13 +602,19 @@ Curl_cookie_add(struct Curl_easy *data, * "the rest". Prefixes must start with '__' and end with a '-', so * only test for names where that can possibly be true. */ - if(nlen > 3 && name[0] == '_' && name[1] == '_') { - if(strncasecompare("__Secure-", name, 9)) + if(nlen >= 7 && namep[0] == '_' && namep[1] == '_') { + if(strncasecompare("__Secure-", namep, 9)) co->prefix |= COOKIE_PREFIX__SECURE; - else if(strncasecompare("__Host-", name, 7)) + else if(strncasecompare("__Host-", namep, 7)) co->prefix |= COOKIE_PREFIX__HOST; } + /* + * Use strstore() below to properly deal with received cookie + * headers that have the same string property set more than once, + * and then we use the last one. + */ + if(!co->name) { /* The very first name/value pair is the actual cookie name */ if(!sep) { @@ -615,20 +622,20 @@ Curl_cookie_add(struct Curl_easy *data, badcookie = TRUE; break; } - co->name = strdup(name); - co->value = strdup(whatptr); + strstore(&co->name, namep, nlen); + strstore(&co->value, valuep, vlen); done = TRUE; if(!co->name || !co->value) { badcookie = TRUE; break; } - if(invalid_octets(whatptr) || invalid_octets(name)) { + if(invalid_octets(co->value) || invalid_octets(co->name)) { infof(data, "invalid octets in name/value, cookie dropped"); badcookie = TRUE; break; } } - else if(!len) { + else if(!vlen) { /* * this was a "<name>=" with no content, and we must allow * 'secure' and 'httponly' specified this weirdly @@ -639,7 +646,7 @@ Curl_cookie_add(struct Curl_easy *data, * using a secure protocol, or when the cookie is being set by * reading from file */ - if(strcasecompare("secure", name)) { + if((nlen == 6) && strncasecompare("secure", namep, 6)) { if(secure || !c->running) { co->secure = TRUE; } @@ -648,7 +655,7 @@ Curl_cookie_add(struct Curl_easy *data, break; } } - else if(strcasecompare("httponly", name)) + else if((nlen == 8) && strncasecompare("httponly", namep, 8)) co->httponly = TRUE; else if(sep) /* there was a '=' so we're not done parsing this field */ @@ -656,8 +663,8 @@ Curl_cookie_add(struct Curl_easy *data, } if(done) ; - else if(strcasecompare("path", name)) { - strstore(&co->path, whatptr); + else if((nlen == 4) && strncasecompare("path", namep, 4)) { + strstore(&co->path, valuep, vlen); if(!co->path) { badcookie = TRUE; /* out of memory bad */ break; @@ -669,7 +676,8 @@ Curl_cookie_add(struct Curl_easy *data, break; } } - else if(strcasecompare("domain", name) && whatptr[0]) { + else if((nlen == 6) && + strncasecompare("domain", namep, 6) && vlen) { bool is_ip; /* @@ -677,8 +685,10 @@ Curl_cookie_add(struct Curl_easy *data, * the given domain is not valid and thus cannot be set. */ - if('.' == whatptr[0]) - whatptr++; /* ignore preceding dot */ + if('.' == valuep[0]) { + valuep++; /* ignore preceding dot */ + vlen--; + } #ifndef USE_LIBPSL /* @@ -686,16 +696,17 @@ Curl_cookie_add(struct Curl_easy *data, * TLD or otherwise "protected" suffix. To reduce risk, we require a * dot OR the exact host name being "localhost". */ - if(bad_domain(whatptr)) + if(bad_domain(valuep, vlen)) domain = ":"; #endif - is_ip = Curl_host_is_ipnum(domain ? domain : whatptr); + is_ip = Curl_host_is_ipnum(domain ? domain : valuep); if(!domain - || (is_ip && !strcmp(whatptr, domain)) - || (!is_ip && tailmatch(whatptr, domain))) { - strstore(&co->domain, whatptr); + || (is_ip && !strncmp(valuep, domain, vlen) && + (vlen == strlen(domain))) + || (!is_ip && tailmatch(valuep, vlen, domain))) { + strstore(&co->domain, valuep, vlen); if(!co->domain) { badcookie = TRUE; break; @@ -711,17 +722,17 @@ Curl_cookie_add(struct Curl_easy *data, */ badcookie = TRUE; infof(data, "skipped cookie with bad tailmatch domain: %s", - whatptr); + valuep); } } - else if(strcasecompare("version", name)) { - strstore(&co->version, whatptr); + else if((nlen == 7) && strncasecompare("version", namep, 7)) { + strstore(&co->version, valuep, vlen); if(!co->version) { badcookie = TRUE; break; } } - else if(strcasecompare("max-age", name)) { + else if((nlen == 7) && strncasecompare("max-age", namep, 7)) { /* * Defined in RFC2109: * @@ -731,14 +742,14 @@ Curl_cookie_add(struct Curl_easy *data, * client should discard the cookie. A value of zero means the * cookie should be discarded immediately. */ - strstore(&co->maxage, whatptr); + strstore(&co->maxage, valuep, vlen); if(!co->maxage) { badcookie = TRUE; break; } } - else if(strcasecompare("expires", name)) { - strstore(&co->expirestr, whatptr); + else if((nlen == 7) && strncasecompare("expires", namep, 7)) { + strstore(&co->expirestr, valuep, vlen); if(!co->expirestr) { badcookie = TRUE; break; @@ -753,24 +764,13 @@ Curl_cookie_add(struct Curl_easy *data, /* this is an "illegal" <what>=<this> pair */ } - if(!semiptr || !*semiptr) { - /* we already know there are no more cookies */ - semiptr = NULL; - continue; - } - - ptr = semiptr + 1; while(*ptr && ISBLANK(*ptr)) ptr++; - semiptr = strchr(ptr, ';'); /* now, find the next semicolon */ - - if(!semiptr && *ptr) - /* - * There are no more semicolons, but there's a final name=value pair - * coming up - */ - semiptr = strchr(ptr, '\0'); - } while(semiptr); + if(*ptr == ';') + ptr++; + else + break; + } while(1); if(co->maxage) { CURLofft offt; @@ -1057,7 +1057,7 @@ Curl_cookie_add(struct Curl_easy *data, Curl_psl_release(data); } else - acceptable = !bad_domain(domain); + acceptable = !bad_domain(domain, strlen(domain)); if(!acceptable) { infof(data, "cookie '%s' dropped, domain '%s' must not " @@ -1447,7 +1447,8 @@ struct Cookie *Curl_cookie_getlist(struct Curl_easy *data, /* now check if the domain is correct */ if(!co->domain || - (co->tailmatch && !is_ip && tailmatch(co->domain, host)) || + (co->tailmatch && !is_ip && + tailmatch(co->domain, co->domain? strlen(co->domain):0, host)) || ((!co->tailmatch || is_ip) && strcasecompare(host, co->domain)) ) { /* * the right part of the host matches the domain stuff in the @@ -1798,11 +1799,6 @@ void Curl_flush_cookies(struct Curl_easy *data, bool cleanup) CURLcode res; if(data->set.str[STRING_COOKIEJAR]) { - /* If there is a list of cookie files to read, do it first so that - we have all the told files read before we write the new jar. - Curl_cookie_loadfiles() LOCKS and UNLOCKS the share itself! */ - Curl_cookie_loadfiles(data); - Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); /* if we have a destination file for all the cookies to get dumped to */ diff --git a/Utilities/cmcurl/lib/curl_gssapi.c b/Utilities/cmcurl/lib/curl_gssapi.c index c4c4f88..c6fe125 100644 --- a/Utilities/cmcurl/lib/curl_gssapi.c +++ b/Utilities/cmcurl/lib/curl_gssapi.c @@ -34,10 +34,16 @@ #include "curl_memory.h" #include "memdebug.h" -gss_OID_desc Curl_spnego_mech_oid = { +#if defined(__GNUC__) +#define CURL_ALIGN8 __attribute__ ((aligned(8))) +#else +#define CURL_ALIGN8 +#endif + +gss_OID_desc Curl_spnego_mech_oid CURL_ALIGN8 = { 6, (char *)"\x2b\x06\x01\x05\x05\x02" }; -gss_OID_desc Curl_krb5_mech_oid = { +gss_OID_desc Curl_krb5_mech_oid CURL_ALIGN8 = { 9, (char *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x02" }; diff --git a/Utilities/cmcurl/lib/curl_log.c b/Utilities/cmcurl/lib/curl_log.c index b5ce1c7..2301cff 100644 --- a/Utilities/cmcurl/lib/curl_log.c +++ b/Utilities/cmcurl/lib/curl_log.c @@ -38,7 +38,7 @@ #include "connect.h" #include "http2.h" #include "http_proxy.h" -#include "cf-http.h" +#include "cf-https-connect.h" #include "socks.h" #include "strtok.h" #include "vtls/vtls.h" diff --git a/Utilities/cmcurl/lib/curl_path.c b/Utilities/cmcurl/lib/curl_path.c index 2df8687..977e533 100644 --- a/Utilities/cmcurl/lib/curl_path.c +++ b/Utilities/cmcurl/lib/curl_path.c @@ -32,70 +32,65 @@ #include "escape.h" #include "memdebug.h" +#define MAX_SSHPATH_LEN 100000 /* arbitrary */ + /* figure out the path to work with in this particular request */ CURLcode Curl_getworkingpath(struct Curl_easy *data, char *homedir, /* when SFTP is used */ char **path) /* returns the allocated real path to work with */ { - char *real_path = NULL; char *working_path; size_t working_path_len; + struct dynbuf npath; CURLcode result = Curl_urldecode(data->state.up.path, 0, &working_path, &working_path_len, REJECT_ZERO); if(result) return result; + /* new path to switch to in case we need to */ + Curl_dyn_init(&npath, MAX_SSHPATH_LEN); + /* Check for /~/, indicating relative to the user's home directory */ - if(data->conn->handler->protocol & CURLPROTO_SCP) { - real_path = malloc(working_path_len + 1); - if(!real_path) { + if((data->conn->handler->protocol & CURLPROTO_SCP) && + (working_path_len > 3) && (!memcmp(working_path, "/~/", 3))) { + /* It is referenced to the home directory, so strip the leading '/~/' */ + if(Curl_dyn_addn(&npath, &working_path[3], working_path_len - 3)) { free(working_path); return CURLE_OUT_OF_MEMORY; } - if((working_path_len > 3) && (!memcmp(working_path, "/~/", 3))) - /* It is referenced to the home directory, so strip the leading '/~/' */ - memcpy(real_path, working_path + 3, working_path_len - 2); - else - memcpy(real_path, working_path, 1 + working_path_len); } - else if(data->conn->handler->protocol & CURLPROTO_SFTP) { - if((working_path_len > 1) && (working_path[1] == '~')) { - size_t homelen = strlen(homedir); - real_path = malloc(homelen + working_path_len + 1); - if(!real_path) { - free(working_path); - return CURLE_OUT_OF_MEMORY; - } - /* It is referenced to the home directory, so strip the - leading '/' */ - memcpy(real_path, homedir, homelen); - /* Only add a trailing '/' if homedir does not end with one */ - if(homelen == 0 || real_path[homelen - 1] != '/') { - real_path[homelen] = '/'; - homelen++; - real_path[homelen] = '\0'; - } - if(working_path_len > 3) { - memcpy(real_path + homelen, working_path + 3, - 1 + working_path_len -3); - } + else if((data->conn->handler->protocol & CURLPROTO_SFTP) && + (working_path_len > 2) && !memcmp(working_path, "/~/", 3)) { + size_t len; + const char *p; + int copyfrom = 3; + if(Curl_dyn_add(&npath, homedir)) { + free(working_path); + return CURLE_OUT_OF_MEMORY; } - else { - real_path = malloc(working_path_len + 1); - if(!real_path) { - free(working_path); - return CURLE_OUT_OF_MEMORY; - } - memcpy(real_path, working_path, 1 + working_path_len); + /* Copy a separating '/' if homedir does not end with one */ + len = Curl_dyn_len(&npath); + p = Curl_dyn_ptr(&npath); + if(len && (p[len-1] != '/')) + copyfrom = 2; + + if(Curl_dyn_addn(&npath, + &working_path[copyfrom], working_path_len - copyfrom)) { + free(working_path); + return CURLE_OUT_OF_MEMORY; } } - free(working_path); + if(Curl_dyn_len(&npath)) { + free(working_path); - /* store the pointer for the caller to receive */ - *path = real_path; + /* store the pointer for the caller to receive */ + *path = Curl_dyn_ptr(&npath); + } + else + *path = working_path; return CURLE_OK; } diff --git a/Utilities/cmcurl/lib/curl_setup.h b/Utilities/cmcurl/lib/curl_setup.h index b58f813..06fb613 100644 --- a/Utilities/cmcurl/lib/curl_setup.h +++ b/Utilities/cmcurl/lib/curl_setup.h @@ -456,8 +456,8 @@ # endif #endif -#if (SIZEOF_CURL_OFF_T == 4) -# define CURL_OFF_T_MAX CURL_OFF_T_C(0x7FFFFFFF) +#if (SIZEOF_CURL_OFF_T < 8) +#error "too small curl_off_t" #else /* assume SIZEOF_CURL_OFF_T == 8 */ # define CURL_OFF_T_MAX CURL_OFF_T_C(0x7FFFFFFFFFFFFFFF) diff --git a/Utilities/cmcurl/lib/curl_setup_once.h b/Utilities/cmcurl/lib/curl_setup_once.h index e68eb50..dde7229 100644 --- a/Utilities/cmcurl/lib/curl_setup_once.h +++ b/Utilities/cmcurl/lib/curl_setup_once.h @@ -69,6 +69,14 @@ #include <unistd.h> #endif +#ifdef USE_WOLFSSL +# if defined(HAVE_STDINT_H) +# include <stdint.h> +# elif defined(HAVE_INTTYPES_H) +# include <inttypes.h> +# endif +#endif + #ifdef __hpux # if !defined(_XOPEN_SOURCE_EXTENDED) || defined(_KERNEL) # ifdef _APP32_64BIT_OFF_T diff --git a/Utilities/cmcurl/lib/doh.c b/Utilities/cmcurl/lib/doh.c index 2e6a377..922d757 100644 --- a/Utilities/cmcurl/lib/doh.c +++ b/Utilities/cmcurl/lib/doh.c @@ -952,7 +952,7 @@ CURLcode Curl_doh_is_resolved(struct Curl_easy *data, Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); /* we got a response, store it in the cache */ - dns = Curl_cache_addr(data, ai, dohp->host, dohp->port); + dns = Curl_cache_addr(data, ai, dohp->host, 0, dohp->port); if(data->share) Curl_share_unlock(data, CURL_LOCK_DATA_DNS); diff --git a/Utilities/cmcurl/lib/dynbuf.c b/Utilities/cmcurl/lib/dynbuf.c index 847f6f6..bd3b935 100644 --- a/Utilities/cmcurl/lib/dynbuf.c +++ b/Utilities/cmcurl/lib/dynbuf.c @@ -99,8 +99,7 @@ static CURLcode dyn_nappend(struct dynbuf *s, include that as well when it uses this code */ void *p = realloc(s->bufr, a); if(!p) { - Curl_safefree(s->bufr); - s->leng = s->allc = 0; + Curl_dyn_free(s); return CURLE_OUT_OF_MEMORY; } s->bufr = p; diff --git a/Utilities/cmcurl/lib/easy.c b/Utilities/cmcurl/lib/easy.c index db03026..27124a7 100644 --- a/Utilities/cmcurl/lib/easy.c +++ b/Utilities/cmcurl/lib/easy.c @@ -1228,7 +1228,6 @@ CURLcode curl_easy_recv(struct Curl_easy *data, void *buffer, size_t buflen, return result; *n = (size_t)n1; - infof(data, "reached %s:%d", __FILE__, __LINE__); return CURLE_OK; } diff --git a/Utilities/cmcurl/lib/ftp.c b/Utilities/cmcurl/lib/ftp.c index 8c72874..ef9ec1e 100644 --- a/Utilities/cmcurl/lib/ftp.c +++ b/Utilities/cmcurl/lib/ftp.c @@ -436,6 +436,12 @@ static CURLcode InitiateTransfer(struct Curl_easy *data) bool connected; DEBUGF(infof(data, "ftp InitiateTransfer()")); + if(conn->bits.ftp_use_data_ssl && data->set.ftp_use_port && + !Curl_conn_is_ssl(conn, SECONDARYSOCKET)) { + result = Curl_ssl_cfilter_add(data, conn, SECONDARYSOCKET); + if(result) + return result; + } result = Curl_conn_connect(data, SECONDARYSOCKET, TRUE, &connected); if(result || !connected) return result; @@ -1795,6 +1801,29 @@ static char *control_address(struct connectdata *conn) return conn->primary_ip; } +static bool match_pasv_6nums(const char *p, + unsigned int *array) /* 6 numbers */ +{ + int i; + for(i = 0; i < 6; i++) { + unsigned long num; + char *endp; + if(i) { + if(*p != ',') + return FALSE; + p++; + } + if(!ISDIGIT(*p)) + return FALSE; + num = strtoul(p, &endp, 10); + if(num > 255) + return FALSE; + array[i] = (unsigned int)num; + p = endp; + } + return TRUE; +} + static CURLcode ftp_state_pasv_resp(struct Curl_easy *data, int ftpcode) { @@ -1814,27 +1843,18 @@ static CURLcode ftp_state_pasv_resp(struct Curl_easy *data, /* positive EPSV response */ char *ptr = strchr(str, '('); if(ptr) { - unsigned int num; - char separator[4]; + char sep; ptr++; - if(5 == sscanf(ptr, "%c%c%c%u%c", - &separator[0], - &separator[1], - &separator[2], - &num, - &separator[3])) { - const char sep1 = separator[0]; - int i; - - /* The four separators should be identical, or else this is an oddly - formatted reply and we bail out immediately. */ - for(i = 1; i<4; i++) { - if(separator[i] != sep1) { - ptr = NULL; /* set to NULL to signal error */ - break; - } - } - if(num > 0xffff) { + /* |||12345| */ + sep = ptr[0]; + /* the ISDIGIT() check here is because strtoul() accepts leading minus + etc */ + if((ptr[1] == sep) && (ptr[2] == sep) && ISDIGIT(ptr[3])) { + char *endp; + unsigned long num = strtoul(&ptr[3], &endp, 10); + if(*endp != sep) + ptr = NULL; + else if(num > 0xffff) { failf(data, "Illegal port number in EPSV reply"); return CURLE_FTP_WEIRD_PASV_REPLY; } @@ -1856,8 +1876,7 @@ static CURLcode ftp_state_pasv_resp(struct Curl_easy *data, else if((ftpc->count1 == 1) && (ftpcode == 227)) { /* positive PASV response */ - unsigned int ip[4] = {0, 0, 0, 0}; - unsigned int port[2] = {0, 0}; + unsigned int ip[6]; /* * Scan for a sequence of six comma-separated numbers and use them as @@ -1869,15 +1888,12 @@ static CURLcode ftp_state_pasv_resp(struct Curl_easy *data, * "227 Entering passive mode. 127,0,0,1,4,51" */ while(*str) { - if(6 == sscanf(str, "%u,%u,%u,%u,%u,%u", - &ip[0], &ip[1], &ip[2], &ip[3], - &port[0], &port[1])) + if(match_pasv_6nums(str, ip)) break; str++; } - if(!*str || (ip[0] > 255) || (ip[1] > 255) || (ip[2] > 255) || - (ip[3] > 255) || (port[0] > 255) || (port[1] > 255) ) { + if(!*str) { failf(data, "Couldn't interpret the 227-response"); return CURLE_FTP_WEIRD_227_FORMAT; } @@ -1897,7 +1913,7 @@ static CURLcode ftp_state_pasv_resp(struct Curl_easy *data, if(!ftpc->newhost) return CURLE_OUT_OF_MEMORY; - ftpc->newport = (unsigned short)(((port[0]<<8) + port[1]) & 0xffff); + ftpc->newport = (unsigned short)(((ip[4]<<8) + ip[5]) & 0xffff); } else if(ftpc->count1 == 0) { /* EPSV failed, move on to PASV */ @@ -2032,6 +2048,30 @@ static CURLcode ftp_state_port_resp(struct Curl_easy *data, return result; } +static int twodigit(const char *p) +{ + return (p[0]-'0') * 10 + (p[1]-'0'); +} + +static bool ftp_213_date(const char *p, int *year, int *month, int *day, + int *hour, int *minute, int *second) +{ + size_t len = strlen(p); + if(len < 14) + return FALSE; + *year = twodigit(&p[0]) * 100 + twodigit(&p[2]); + *month = twodigit(&p[4]); + *day = twodigit(&p[6]); + *hour = twodigit(&p[8]); + *minute = twodigit(&p[10]); + *second = twodigit(&p[12]); + + if((*month > 12) || (*day > 31) || (*hour > 23) || (*minute > 59) || + (*second > 60)) + return FALSE; + return TRUE; +} + static CURLcode ftp_state_mdtm_resp(struct Curl_easy *data, int ftpcode) { @@ -2046,8 +2086,8 @@ static CURLcode ftp_state_mdtm_resp(struct Curl_easy *data, /* we got a time. Format should be: "YYYYMMDDHHMMSS[.sss]" where the last .sss part is optional and means fractions of a second */ int year, month, day, hour, minute, second; - if(6 == sscanf(&data->state.buffer[4], "%04d%02d%02d%02d%02d%02d", - &year, &month, &day, &hour, &minute, &second)) { + if(ftp_213_date(&data->state.buffer[4], + &year, &month, &day, &hour, &minute, &second)) { /* we have a time, reformat it */ char timebuf[24]; msnprintf(timebuf, sizeof(timebuf), @@ -2635,7 +2675,7 @@ static CURLcode ftp_statemachine(struct Curl_easy *data, int ftpcode; struct ftp_conn *ftpc = &conn->proto.ftpc; struct pingpong *pp = &ftpc->pp; - static const char ftpauth[][4] = { "SSL", "TLS" }; + static const char * const ftpauth[] = { "SSL", "TLS" }; size_t nread = 0; if(pp->sendleft) @@ -3221,7 +3261,7 @@ static CURLcode ftp_done(struct Curl_easy *data, CURLcode status, if(data->state.wildcardmatch) { if(data->set.chunk_end && ftpc->file) { Curl_set_in_callback(data, true); - data->set.chunk_end(data->wildcard.customptr); + data->set.chunk_end(data->set.wildcardptr); Curl_set_in_callback(data, false); } ftpc->known_filesize = -1; @@ -3728,7 +3768,7 @@ static CURLcode init_wc_data(struct Curl_easy *data) char *last_slash; struct FTP *ftp = data->req.p.ftp; char *path = ftp->path; - struct WildcardData *wildcard = &(data->wildcard); + struct WildcardData *wildcard = data->wildcard; CURLcode result = CURLE_OK; struct ftp_wc *ftpwc = NULL; @@ -3776,7 +3816,7 @@ static CURLcode init_wc_data(struct Curl_easy *data) goto fail; } - wildcard->protdata = ftpwc; /* put it to the WildcardData tmp pointer */ + wildcard->ftpwc = ftpwc; /* put it to the WildcardData tmp pointer */ wildcard->dtor = wc_data_dtor; /* wildcard does not support NOCWD option (assert it?) */ @@ -3814,13 +3854,13 @@ static CURLcode init_wc_data(struct Curl_easy *data) } Curl_safefree(wildcard->pattern); wildcard->dtor = ZERO_NULL; - wildcard->protdata = NULL; + wildcard->ftpwc = NULL; return result; } static CURLcode wc_statemach(struct Curl_easy *data) { - struct WildcardData * const wildcard = &(data->wildcard); + struct WildcardData * const wildcard = data->wildcard; struct connectdata *conn = data->conn; CURLcode result = CURLE_OK; @@ -3837,7 +3877,7 @@ static CURLcode wc_statemach(struct Curl_easy *data) case CURLWC_MATCHING: { /* In this state is LIST response successfully parsed, so lets restore previous WRITEFUNCTION callback and WRITEDATA pointer */ - struct ftp_wc *ftpwc = wildcard->protdata; + struct ftp_wc *ftpwc = wildcard->ftpwc; data->set.fwrite_func = ftpwc->backup.write_function; data->set.out = ftpwc->backup.file_descriptor; ftpwc->backup.write_function = ZERO_NULL; @@ -3876,7 +3916,7 @@ static CURLcode wc_statemach(struct Curl_easy *data) long userresponse; Curl_set_in_callback(data, true); userresponse = data->set.chunk_bgn( - finfo, wildcard->customptr, (int)wildcard->filelist.size); + finfo, data->set.wildcardptr, (int)wildcard->filelist.size); Curl_set_in_callback(data, false); switch(userresponse) { case CURL_CHUNK_BGN_FUNC_SKIP: @@ -3916,7 +3956,7 @@ static CURLcode wc_statemach(struct Curl_easy *data) case CURLWC_SKIP: { if(data->set.chunk_end) { Curl_set_in_callback(data, true); - data->set.chunk_end(data->wildcard.customptr); + data->set.chunk_end(data->set.wildcardptr); Curl_set_in_callback(data, false); } Curl_llist_remove(&wildcard->filelist, wildcard->filelist.head, NULL); @@ -3926,7 +3966,7 @@ static CURLcode wc_statemach(struct Curl_easy *data) } case CURLWC_CLEAN: { - struct ftp_wc *ftpwc = wildcard->protdata; + struct ftp_wc *ftpwc = wildcard->ftpwc; result = CURLE_OK; if(ftpwc) result = Curl_ftp_parselist_geterror(ftpwc->parser); @@ -3939,7 +3979,7 @@ static CURLcode wc_statemach(struct Curl_easy *data) case CURLWC_ERROR: case CURLWC_CLEAR: if(wildcard->dtor) - wildcard->dtor(wildcard->protdata); + wildcard->dtor(wildcard->ftpwc); return result; } } @@ -3966,8 +4006,8 @@ static CURLcode ftp_do(struct Curl_easy *data, bool *done) if(data->state.wildcardmatch) { result = wc_statemach(data); - if(data->wildcard.state == CURLWC_SKIP || - data->wildcard.state == CURLWC_DONE) { + if(data->wildcard->state == CURLWC_SKIP || + data->wildcard->state == CURLWC_DONE) { /* do not call ftp_regular_transfer */ return CURLE_OK; } @@ -4053,6 +4093,8 @@ static CURLcode ftp_disconnect(struct Curl_easy *data, } freedirs(ftpc); + Curl_safefree(ftpc->account); + Curl_safefree(ftpc->alternative_to_user); Curl_safefree(ftpc->prevpath); Curl_safefree(ftpc->server_os); Curl_pp_disconnect(pp); @@ -4322,11 +4364,31 @@ static CURLcode ftp_setup_connection(struct Curl_easy *data, char *type; struct FTP *ftp; CURLcode result = CURLE_OK; + struct ftp_conn *ftpc = &conn->proto.ftpc; - data->req.p.ftp = ftp = calloc(sizeof(struct FTP), 1); + ftp = calloc(sizeof(struct FTP), 1); if(!ftp) return CURLE_OUT_OF_MEMORY; + /* clone connection related data that is FTP specific */ + if(data->set.str[STRING_FTP_ACCOUNT]) { + ftpc->account = strdup(data->set.str[STRING_FTP_ACCOUNT]); + if(!ftpc->account) { + free(ftp); + return CURLE_OUT_OF_MEMORY; + } + } + if(data->set.str[STRING_FTP_ALTERNATIVE_TO_USER]) { + ftpc->alternative_to_user = + strdup(data->set.str[STRING_FTP_ALTERNATIVE_TO_USER]); + if(!ftpc->alternative_to_user) { + Curl_safefree(ftpc->account); + free(ftp); + return CURLE_OUT_OF_MEMORY; + } + } + data->req.p.ftp = ftp; + ftp->path = &data->state.up.path[1]; /* don't include the initial slash */ /* FTP URLs support an extension like ";type=<typecode>" that @@ -4361,7 +4423,9 @@ static CURLcode ftp_setup_connection(struct Curl_easy *data, /* get some initial data into the ftp struct */ ftp->transfer = PPTRANSFER_BODY; ftp->downloadsize = 0; - conn->proto.ftpc.known_filesize = -1; /* unknown size for now */ + ftpc->known_filesize = -1; /* unknown size for now */ + ftpc->use_ssl = data->set.use_ssl; + ftpc->ccc = data->set.ftp_ccc; return result; } diff --git a/Utilities/cmcurl/lib/ftp.h b/Utilities/cmcurl/lib/ftp.h index 65efa6f..977fc88 100644 --- a/Utilities/cmcurl/lib/ftp.h +++ b/Utilities/cmcurl/lib/ftp.h @@ -120,6 +120,8 @@ struct FTP { struct */ struct ftp_conn { struct pingpong pp; + char *account; + char *alternative_to_user; char *entrypath; /* the PWD reply when we logged on */ char *file; /* url-decoded file name (or path) */ char **dirs; /* realloc()ed array for path components */ @@ -143,6 +145,9 @@ struct ftp_conn { ftpstate state; /* always use ftp.c:state() to change state! */ ftpstate state_saved; /* transfer type saved to be reloaded after data connection is established */ + unsigned char use_ssl; /* if AUTH TLS is to be attempted etc, for FTP or + IMAP or POP3 or others! (type: curl_usessl)*/ + unsigned char ccc; /* ccc level for this connection */ BIT(ftp_trying_alternative); BIT(dont_check); /* Set to TRUE to prevent the final (post-transfer) file size and 226/250 status check. It should still diff --git a/Utilities/cmcurl/lib/ftplistparser.c b/Utilities/cmcurl/lib/ftplistparser.c index f7c6434..39001e3 100644 --- a/Utilities/cmcurl/lib/ftplistparser.c +++ b/Utilities/cmcurl/lib/ftplistparser.c @@ -181,6 +181,43 @@ struct ftp_parselist_data { } offsets; }; +static void fileinfo_dtor(void *user, void *element) +{ + (void)user; + Curl_fileinfo_cleanup(element); +} + +CURLcode Curl_wildcard_init(struct WildcardData *wc) +{ + Curl_llist_init(&wc->filelist, fileinfo_dtor); + wc->state = CURLWC_INIT; + + return CURLE_OK; +} + +void Curl_wildcard_dtor(struct WildcardData **wcp) +{ + struct WildcardData *wc = *wcp; + if(!wc) + return; + + if(wc->dtor) { + wc->dtor(wc->ftpwc); + wc->dtor = ZERO_NULL; + wc->ftpwc = NULL; + } + DEBUGASSERT(wc->ftpwc == NULL); + + Curl_llist_destroy(&wc->filelist, NULL); + free(wc->path); + wc->path = NULL; + free(wc->pattern); + wc->pattern = NULL; + wc->state = CURLWC_INIT; + free(wc); + *wcp = NULL; +} + struct ftp_parselist_data *Curl_ftp_parselist_data_alloc(void) { return calloc(1, sizeof(struct ftp_parselist_data)); @@ -274,8 +311,8 @@ static CURLcode ftp_pl_insert_finfo(struct Curl_easy *data, struct fileinfo *infop) { curl_fnmatch_callback compare; - struct WildcardData *wc = &data->wildcard; - struct ftp_wc *ftpwc = wc->protdata; + struct WildcardData *wc = data->wildcard; + struct ftp_wc *ftpwc = wc->ftpwc; struct Curl_llist *llist = &wc->filelist; struct ftp_parselist_data *parser = ftpwc->parser; bool add = TRUE; @@ -330,7 +367,7 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb, { size_t bufflen = size*nmemb; struct Curl_easy *data = (struct Curl_easy *)connptr; - struct ftp_wc *ftpwc = data->wildcard.protdata; + struct ftp_wc *ftpwc = data->wildcard->ftpwc; struct ftp_parselist_data *parser = ftpwc->parser; struct fileinfo *infop; struct curl_fileinfo *finfo; diff --git a/Utilities/cmcurl/lib/ftplistparser.h b/Utilities/cmcurl/lib/ftplistparser.h index 3d9a43b..5ba1f6a 100644 --- a/Utilities/cmcurl/lib/ftplistparser.h +++ b/Utilities/cmcurl/lib/ftplistparser.h @@ -39,5 +39,39 @@ struct ftp_parselist_data *Curl_ftp_parselist_data_alloc(void); void Curl_ftp_parselist_data_free(struct ftp_parselist_data **pl_data); +/* list of wildcard process states */ +typedef enum { + CURLWC_CLEAR = 0, + CURLWC_INIT = 1, + CURLWC_MATCHING, /* library is trying to get list of addresses for + downloading */ + CURLWC_DOWNLOADING, + CURLWC_CLEAN, /* deallocate resources and reset settings */ + CURLWC_SKIP, /* skip over concrete file */ + CURLWC_ERROR, /* error cases */ + CURLWC_DONE /* if is wildcard->state == CURLWC_DONE wildcard loop + will end */ +} wildcard_states; + +typedef void (*wildcard_dtor)(void *ptr); + +/* struct keeping information about wildcard download process */ +struct WildcardData { + char *path; /* path to the directory, where we trying wildcard-match */ + char *pattern; /* wildcard pattern */ + struct Curl_llist filelist; /* llist with struct Curl_fileinfo */ + struct ftp_wc *ftpwc; /* pointer to FTP wildcard data */ + wildcard_dtor dtor; + unsigned char state; /* wildcard_states */ +}; + +CURLcode Curl_wildcard_init(struct WildcardData *wc); +void Curl_wildcard_dtor(struct WildcardData **wcp); + +struct Curl_easy; + +#else +/* FTP is disabled */ +#define Curl_wildcard_dtor(x) #endif /* CURL_DISABLE_FTP */ #endif /* HEADER_CURL_FTPLISTPARSER_H */ diff --git a/Utilities/cmcurl/lib/headers.c b/Utilities/cmcurl/lib/headers.c index 22e0e01..6cd7e31 100644 --- a/Utilities/cmcurl/lib/headers.c +++ b/Utilities/cmcurl/lib/headers.c @@ -38,14 +38,13 @@ /* Generate the curl_header struct for the user. This function MUST assign all struct fields in the output struct. */ -static void copy_header_external(struct Curl_easy *data, - struct Curl_header_store *hs, +static void copy_header_external(struct Curl_header_store *hs, size_t index, size_t amount, struct Curl_llist_element *e, - struct curl_header **hout) + struct curl_header *hout) { - struct curl_header *h = *hout = &data->state.headerout; + struct curl_header *h = hout; h->name = hs->name; h->value = hs->value; h->amount = amount; @@ -118,7 +117,9 @@ CURLHcode curl_easy_header(CURL *easy, return CURLHE_MISSING; } /* this is the name we want */ - copy_header_external(data, hs, nameindex, amount, e_pick, hout); + copy_header_external(hs, nameindex, amount, e_pick, + &data->state.headerout[0]); + *hout = &data->state.headerout[0]; return CURLHE_OK; } @@ -132,7 +133,6 @@ struct curl_header *curl_easy_nextheader(CURL *easy, struct Curl_llist_element *pick; struct Curl_llist_element *e; struct Curl_header_store *hs; - struct curl_header *hout; size_t amount = 0; size_t index = 0; @@ -179,8 +179,9 @@ struct curl_header *curl_easy_nextheader(CURL *easy, index = amount - 1; } - copy_header_external(data, hs, index, amount, pick, &hout); - return hout; + copy_header_external(hs, index, amount, pick, + &data->state.headerout[1]); + return &data->state.headerout[1]; } static CURLcode namevalue(char *header, size_t hlen, unsigned int type, diff --git a/Utilities/cmcurl/lib/hostasyn.c b/Utilities/cmcurl/lib/hostasyn.c index 536eb73..2f6762c 100644 --- a/Utilities/cmcurl/lib/hostasyn.c +++ b/Utilities/cmcurl/lib/hostasyn.c @@ -78,7 +78,7 @@ CURLcode Curl_addrinfo_callback(struct Curl_easy *data, Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); dns = Curl_cache_addr(data, ai, - data->state.async.hostname, + data->state.async.hostname, 0, data->state.async.port); if(data->share) Curl_share_unlock(data, CURL_LOCK_DATA_DNS); diff --git a/Utilities/cmcurl/lib/hostip.c b/Utilities/cmcurl/lib/hostip.c index 9738806..d0dc2e8 100644 --- a/Utilities/cmcurl/lib/hostip.c +++ b/Utilities/cmcurl/lib/hostip.c @@ -167,18 +167,25 @@ void Curl_printable_address(const struct Curl_addrinfo *ai, char *buf, /* * Create a hostcache id string for the provided host + port, to be used by - * the DNS caching. Without alloc. + * the DNS caching. Without alloc. Return length of the id string. */ -static void -create_hostcache_id(const char *name, int port, char *ptr, size_t buflen) +static size_t +create_hostcache_id(const char *name, + size_t nlen, /* 0 or actual name length */ + int port, char *ptr, size_t buflen) { - size_t len = strlen(name); + size_t len = nlen ? nlen : strlen(name); + size_t olen = 0; + DEBUGASSERT(buflen >= MAX_HOSTCACHE_LEN); if(len > (buflen - 7)) len = buflen - 7; /* store and lower case the name */ - while(len--) + while(len--) { *ptr++ = Curl_raw_tolower(*name++); - msnprintf(ptr, 7, ":%u", port); + olen++; + } + olen += msnprintf(ptr, 7, ":%u", port); + return olen; } struct hostcache_prune_data { @@ -260,20 +267,18 @@ static struct Curl_dns_entry *fetch_addr(struct Curl_easy *data, int port) { struct Curl_dns_entry *dns = NULL; - size_t entry_len; char entry_id[MAX_HOSTCACHE_LEN]; /* Create an entry id, based upon the hostname and port */ - create_hostcache_id(hostname, port, entry_id, sizeof(entry_id)); - entry_len = strlen(entry_id); + size_t entry_len = create_hostcache_id(hostname, 0, port, + entry_id, sizeof(entry_id)); /* See if its already in our dns cache */ dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len + 1); /* No entry found in cache, check if we might have a wildcard entry */ if(!dns && data->state.wildcard_resolve) { - create_hostcache_id("*", port, entry_id, sizeof(entry_id)); - entry_len = strlen(entry_id); + entry_len = create_hostcache_id("*", 1, port, entry_id, sizeof(entry_id)); /* See if it's already in our dns cache */ dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len + 1); @@ -438,6 +443,7 @@ struct Curl_dns_entry * Curl_cache_addr(struct Curl_easy *data, struct Curl_addrinfo *addr, const char *hostname, + size_t hostlen, /* length or zero */ int port) { char entry_id[MAX_HOSTCACHE_LEN]; @@ -461,8 +467,8 @@ Curl_cache_addr(struct Curl_easy *data, } /* Create an entry id, based upon the hostname and port */ - create_hostcache_id(hostname, port, entry_id, sizeof(entry_id)); - entry_len = strlen(entry_id); + entry_len = create_hostcache_id(hostname, hostlen, port, + entry_id, sizeof(entry_id)); dns->inuse = 1; /* the cache has the first reference */ dns->addr = addr; /* this is the address(es) */ @@ -791,7 +797,7 @@ enum resolve_t Curl_resolv(struct Curl_easy *data, Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); /* we got a response, store it in the cache */ - dns = Curl_cache_addr(data, addr, hostname, port); + dns = Curl_cache_addr(data, addr, hostname, 0, port); if(data->share) Curl_share_unlock(data, CURL_LOCK_DATA_DNS); @@ -1059,8 +1065,7 @@ void Curl_hostcache_clean(struct Curl_easy *data, CURLcode Curl_loadhostpairs(struct Curl_easy *data) { struct curl_slist *hostp; - char hostname[256]; - int port = 0; + char *host_end; /* Default is no wildcard found */ data->state.wildcard_resolve = false; @@ -1070,18 +1075,25 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data) if(!hostp->data) continue; if(hostp->data[0] == '-') { + unsigned long num = 0; size_t entry_len; - - if(2 != sscanf(hostp->data + 1, "%255[^:]:%d", hostname, &port)) { - infof(data, "Couldn't parse CURLOPT_RESOLVE removal entry '%s'", + size_t hlen = 0; + host_end = strchr(&hostp->data[1], ':'); + + if(host_end) { + hlen = host_end - &hostp->data[1]; + num = strtoul(++host_end, NULL, 10); + if(!hlen || (num > 0xffff)) + host_end = NULL; + } + if(!host_end) { + infof(data, "Bad syntax CURLOPT_RESOLVE removal entry '%s'", hostp->data); continue; } - /* Create an entry id, based upon the hostname and port */ - create_hostcache_id(hostname, port, entry_id, sizeof(entry_id)); - entry_len = strlen(entry_id); - + entry_len = create_hostcache_id(&hostp->data[1], hlen, (int)num, + entry_id, sizeof(entry_id)); if(data->share) Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); @@ -1102,25 +1114,22 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data) char *addr_begin; char *addr_end; char *port_ptr; + int port = 0; char *end_ptr; bool permanent = TRUE; - char *host_begin; - char *host_end; unsigned long tmp_port; bool error = true; + char *host_begin = hostp->data; + size_t hlen = 0; - host_begin = hostp->data; if(host_begin[0] == '+') { host_begin++; permanent = FALSE; } host_end = strchr(host_begin, ':'); - if(!host_end || - ((host_end - host_begin) >= (ptrdiff_t)sizeof(hostname))) + if(!host_end) goto err; - - memcpy(hostname, host_begin, host_end - host_begin); - hostname[host_end - host_begin] = '\0'; + hlen = host_end - host_begin; port_ptr = host_end + 1; tmp_port = strtoul(port_ptr, &end_ptr, 10); @@ -1196,8 +1205,8 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data) } /* Create an entry id, based upon the hostname and port */ - create_hostcache_id(hostname, port, entry_id, sizeof(entry_id)); - entry_len = strlen(entry_id); + entry_len = create_hostcache_id(host_begin, hlen, port, + entry_id, sizeof(entry_id)); if(data->share) Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); @@ -1206,8 +1215,8 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data) dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len + 1); if(dns) { - infof(data, "RESOLVE %s:%d is - old addresses discarded", - hostname, port); + infof(data, "RESOLVE %.*s:%d is - old addresses discarded", + (int)hlen, host_begin, port); /* delete old entry, there are two reasons for this 1. old entry may have different addresses. 2. even if entry with correct addresses is already in the cache, @@ -1223,7 +1232,7 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data) } /* put this new host in the cache */ - dns = Curl_cache_addr(data, head, hostname, port); + dns = Curl_cache_addr(data, head, host_begin, hlen, port); if(dns) { if(permanent) dns->timestamp = 0; /* mark as permanent */ @@ -1239,13 +1248,13 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data) Curl_freeaddrinfo(head); return CURLE_OUT_OF_MEMORY; } - infof(data, "Added %s:%d:%s to DNS cache%s", - hostname, port, addresses, permanent ? "" : " (non-permanent)"); + infof(data, "Added %.*s:%d:%s to DNS cache%s", + (int)hlen, host_begin, port, addresses, + permanent ? "" : " (non-permanent)"); /* Wildcard hostname */ - if(hostname[0] == '*' && hostname[1] == '\0') { - infof(data, "RESOLVE %s:%d is wildcard, enabling wildcard checks", - hostname, port); + if((hlen == 1) && (host_begin[0] == '*')) { + infof(data, "RESOLVE *:%d using wildcard", port); data->state.wildcard_resolve = true; } } diff --git a/Utilities/cmcurl/lib/hostip.h b/Utilities/cmcurl/lib/hostip.h index e0d13cd..4b5481f 100644 --- a/Utilities/cmcurl/lib/hostip.h +++ b/Utilities/cmcurl/lib/hostip.h @@ -178,7 +178,7 @@ Curl_fetch_addr(struct Curl_easy *data, */ struct Curl_dns_entry * Curl_cache_addr(struct Curl_easy *data, struct Curl_addrinfo *addr, - const char *hostname, int port); + const char *hostname, size_t hostlen, int port); #ifndef INADDR_NONE #define CURL_INADDR_NONE (in_addr_t) ~0 diff --git a/Utilities/cmcurl/lib/http.c b/Utilities/cmcurl/lib/http.c index cb585e7..faa486c 100644 --- a/Utilities/cmcurl/lib/http.c +++ b/Utilities/cmcurl/lib/http.c @@ -88,6 +88,7 @@ #include "hsts.h" #include "ws.h" #include "c-hyper.h" +#include "curl_ctype.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" @@ -233,15 +234,12 @@ static CURLcode http_setup_conn(struct Curl_easy *data, Curl_mime_initpart(&http->form); data->req.p.http = http; + connkeep(conn, "HTTP default"); - if((data->state.httpwant == CURL_HTTP_VERSION_3) - || (data->state.httpwant == CURL_HTTP_VERSION_3ONLY)) { + if(data->state.httpwant == CURL_HTTP_VERSION_3ONLY) { CURLcode result = Curl_conn_may_http3(data, conn); if(result) return result; - - /* TODO: HTTP lower version eyeballing */ - conn->transport = TRNSPRT_QUIC; } return CURLE_OK; @@ -2342,7 +2340,16 @@ CURLcode Curl_http_bodysend(struct Curl_easy *data, struct connectdata *conn, return result; } - if(http->postsize) { + /* For really small puts we don't use Expect: headers at all, and for + the somewhat bigger ones we allow the app to disable it. Just make + sure that the expect100header is always set to the preferred value + here. */ + ptr = Curl_checkheaders(data, STRCONST("Expect")); + if(ptr) { + data->state.expect100header = + Curl_compareheader(ptr, STRCONST("Expect:"), STRCONST("100-continue")); + } + else if(http->postsize > EXPECT_100_THRESHOLD || http->postsize < 0) { result = expect100(data, conn, r); if(result) return result; @@ -4155,11 +4162,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, if(!k->headerline++) { /* This is the first header, it MUST be the error code line or else we consider this to be the body right away! */ - int httpversion_major; - int rtspversion_major; - int nc = 0; -#define HEADER1 headp /* no conversion needed, just use headp */ - + bool fine_statusline = FALSE; if(conn->handler->protocol & PROTO_FAMILY_HTTP) { /* * https://datatracker.ietf.org/doc/html/rfc7230#section-3.1.2 @@ -4168,39 +4171,60 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, * says. We allow any three-digit number here, but we cannot make * guarantees on future behaviors since it isn't within the protocol. */ - char separator; - char twoorthree[2]; int httpversion = 0; - char digit4 = 0; - nc = sscanf(HEADER1, - " HTTP/%1d.%1d%c%3d%c", - &httpversion_major, - &httpversion, - &separator, - &k->httpcode, - &digit4); - - if(nc == 1 && httpversion_major >= 2 && - 2 == sscanf(HEADER1, " HTTP/%1[23] %d", twoorthree, &k->httpcode)) { - conn->httpversion = 0; - nc = 4; - separator = ' '; - } - - /* There can only be a 4th response code digit stored in 'digit4' if - all the other fields were parsed and stored first, so nc is 5 when - digit4 a digit. - - The sscanf() line above will also allow zero-prefixed and negative - numbers, so we check for that too here. - */ - else if(ISDIGIT(digit4) || (nc >= 4 && k->httpcode < 100)) { - failf(data, "Unsupported response code in HTTP response"); - return CURLE_UNSUPPORTED_PROTOCOL; + char *p = headp; + + while(*p && ISBLANK(*p)) + p++; + if(!strncmp(p, "HTTP/", 5)) { + p += 5; + switch(*p) { + case '1': + p++; + if((p[0] == '.') && (p[1] == '0' || p[1] == '1')) { + if(ISBLANK(p[2])) { + httpversion = 10 + (p[1] - '0'); + p += 3; + if(ISDIGIT(p[0]) && ISDIGIT(p[1]) && ISDIGIT(p[2])) { + k->httpcode = (p[0] - '0') * 100 + (p[1] - '0') * 10 + + (p[2] - '0'); + p += 3; + if(ISSPACE(*p)) + fine_statusline = TRUE; + } + } + } + if(!fine_statusline) { + failf(data, "Unsupported HTTP/1 subversion in response"); + return CURLE_UNSUPPORTED_PROTOCOL; + } + break; + case '2': + case '3': + if(!ISBLANK(p[1])) + break; + httpversion = (*p - '0') * 10; + p += 2; + if(ISDIGIT(p[0]) && ISDIGIT(p[1]) && ISDIGIT(p[2])) { + k->httpcode = (p[0] - '0') * 100 + (p[1] - '0') * 10 + + (p[2] - '0'); + p += 3; + if(!ISSPACE(*p)) + break; + fine_statusline = TRUE; + } + break; + default: /* unsupported */ + failf(data, "Unsupported HTTP version in response"); + return CURLE_UNSUPPORTED_PROTOCOL; + } } - if((nc >= 4) && (' ' == separator)) { - httpversion += 10 * httpversion_major; + if(fine_statusline) { + if(k->httpcode < 100) { + failf(data, "Unsupported response code in HTTP response"); + return CURLE_UNSUPPORTED_PROTOCOL; + } switch(httpversion) { case 10: case 11: @@ -4227,51 +4251,50 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, conn->bundle->multiuse = BUNDLE_NO_MULTIUSE; } } - else if(!nc) { - /* this is the real world, not a Nirvana - NCSA 1.5.x returns this crap when asked for HTTP/1.1 - */ - nc = sscanf(HEADER1, " HTTP %3d", &k->httpcode); - conn->httpversion = 10; - + else { /* If user has set option HTTP200ALIASES, compare header line against list of aliases */ - if(!nc) { - statusline check = - checkhttpprefix(data, - Curl_dyn_ptr(&data->state.headerb), - Curl_dyn_len(&data->state.headerb)); - if(check == STATUS_DONE) { - nc = 1; - k->httpcode = 200; - conn->httpversion = 10; - } + statusline check = + checkhttpprefix(data, + Curl_dyn_ptr(&data->state.headerb), + Curl_dyn_len(&data->state.headerb)); + if(check == STATUS_DONE) { + fine_statusline = TRUE; + k->httpcode = 200; + conn->httpversion = 10; } } - else { - failf(data, "Unsupported HTTP version in response"); - return CURLE_UNSUPPORTED_PROTOCOL; - } } else if(conn->handler->protocol & CURLPROTO_RTSP) { - char separator; - int rtspversion; - nc = sscanf(HEADER1, - " RTSP/%1d.%1d%c%3d", - &rtspversion_major, - &rtspversion, - &separator, - &k->httpcode); - if((nc == 4) && (' ' == separator)) { - conn->httpversion = 11; /* For us, RTSP acts like HTTP 1.1 */ - } - else { - nc = 0; + char *p = headp; + while(*p && ISBLANK(*p)) + p++; + if(!strncmp(p, "RTSP/", 5)) { + p += 5; + if(ISDIGIT(*p)) { + p++; + if((p[0] == '.') && ISDIGIT(p[1])) { + if(ISBLANK(p[2])) { + p += 3; + if(ISDIGIT(p[0]) && ISDIGIT(p[1]) && ISDIGIT(p[2])) { + k->httpcode = (p[0] - '0') * 100 + (p[1] - '0') * 10 + + (p[2] - '0'); + p += 3; + if(ISSPACE(*p)) { + fine_statusline = TRUE; + conn->httpversion = 11; /* RTSP acts like HTTP 1.1 */ + } + } + } + } + } + if(!fine_statusline) + return CURLE_WEIRD_SERVER_REPLY; } } - if(nc) { + if(fine_statusline) { result = Curl_http_statusline(data, conn); if(result) return result; diff --git a/Utilities/cmcurl/lib/http2.c b/Utilities/cmcurl/lib/http2.c index bdb5e73..b0ce87d 100644 --- a/Utilities/cmcurl/lib/http2.c +++ b/Utilities/cmcurl/lib/http2.c @@ -98,7 +98,6 @@ static size_t populate_binsettings(uint8_t *binsettings, struct cf_h2_ctx { nghttp2_session *h2; uint32_t max_concurrent_streams; - bool enable_push; /* The easy handle used in the current filter call, cleared at return */ struct cf_call_data call_data; @@ -116,6 +115,10 @@ struct cf_h2_ctx { int32_t pause_stream_id; /* stream ID which paused nghttp2_session_mem_recv */ size_t drain_total; /* sum of all stream's UrlState.drain */ + int32_t goaway_error; + int32_t last_stream_id; + BIT(goaway); + BIT(enable_push); }; /* How to access `call_data` from a cf_h2 filter */ @@ -364,41 +367,42 @@ static void http2_stream_free(struct HTTP *stream) } /* + * Returns nonzero if current HTTP/2 session should be closed. + */ +static int should_close_session(struct cf_h2_ctx *ctx) +{ + return ctx->drain_total == 0 && !nghttp2_session_want_read(ctx->h2) && + !nghttp2_session_want_write(ctx->h2); +} + +/* * The server may send us data at any point (e.g. PING frames). Therefore, * we cannot assume that an HTTP/2 socket is dead just because it is readable. * * Check the lower filters first and, if successful, peek at the socket * and distinguish between closed and data. */ -static bool http2_connisdead(struct Curl_cfilter *cf, struct Curl_easy *data) +static bool http2_connisalive(struct Curl_cfilter *cf, struct Curl_easy *data, + bool *input_pending) { struct cf_h2_ctx *ctx = cf->ctx; - int sval; - bool dead = TRUE; + bool alive = TRUE; - if(!cf->next || !cf->next->cft->is_alive(cf->next, data)) - return TRUE; + *input_pending = FALSE; + if(!cf->next || !cf->next->cft->is_alive(cf->next, data, input_pending)) + return FALSE; - sval = SOCKET_READABLE(Curl_conn_cf_get_socket(cf, data), 0); - if(sval == 0) { - /* timeout */ - dead = FALSE; - } - else if(sval & CURL_CSELECT_ERR) { - /* socket is in an error state */ - dead = TRUE; - } - else if(sval & CURL_CSELECT_IN) { + if(*input_pending) { /* This happens before we've sent off a request and the connection is not in use by any other transfer, there shouldn't be any data here, only "protocol frames" */ CURLcode result; ssize_t nread = -1; + *input_pending = FALSE; Curl_attach_connection(data, cf->conn); nread = Curl_conn_cf_recv(cf->next, data, ctx->inbuf, H2_BUFSIZE, &result); - dead = FALSE; if(nread != -1) { DEBUGF(LOG_CF(data, cf, "%d bytes stray data read before trying " "h2 connection", (int)nread)); @@ -406,15 +410,19 @@ static bool http2_connisdead(struct Curl_cfilter *cf, struct Curl_easy *data) ctx->inbuflen = nread; if(h2_process_pending_input(cf, data, &result) < 0) /* immediate error, considered dead */ - dead = TRUE; + alive = FALSE; + else { + alive = !should_close_session(ctx); + } } - else + else { /* the read failed so let's say this is dead anyway */ - dead = TRUE; + alive = FALSE; + } Curl_detach_connection(data); } - return dead; + return alive; } static CURLcode http2_send_ping(struct Curl_cfilter *cf, @@ -815,7 +823,7 @@ static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame, ctx->max_concurrent_streams = nghttp2_session_get_remote_settings( session, NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS); ctx->enable_push = nghttp2_session_get_remote_settings( - session, NGHTTP2_SETTINGS_ENABLE_PUSH); + session, NGHTTP2_SETTINGS_ENABLE_PUSH) != 0; DEBUGF(LOG_CF(data, cf, "MAX_CONCURRENT_STREAMS == %d", ctx->max_concurrent_streams)); DEBUGF(LOG_CF(data, cf, "ENABLE_PUSH == %s", @@ -829,9 +837,12 @@ static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame, break; } case NGHTTP2_GOAWAY: + ctx->goaway = TRUE; + ctx->goaway_error = frame->goaway.error_code; + ctx->last_stream_id = frame->goaway.last_stream_id; if(data) { infof(data, "recveived GOAWAY, error=%d, last_stream=%u", - frame->goaway.error_code, frame->goaway.last_stream_id); + ctx->goaway_error, ctx->last_stream_id); multi_connchanged(data->multi); } break; @@ -858,7 +869,7 @@ static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame, switch(frame->hd.type) { case NGHTTP2_DATA: - /* If body started on this stream, then receiving DATA is illegal. */ + /* If !body started on this stream, then receiving DATA is illegal. */ DEBUGF(LOG_CF(data_s, cf, "[h2sid=%u] recv frame DATA", stream_id)); if(!stream->bodystarted) { rv = nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE, @@ -940,7 +951,21 @@ static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame, break; case NGHTTP2_RST_STREAM: DEBUGF(LOG_CF(data_s, cf, "[h2sid=%u] recv RST", stream_id)); + stream->closed = TRUE; stream->reset = TRUE; + drain_this(cf, data); + Curl_expire(data, 0, EXPIRE_RUN_NOW); + break; + case NGHTTP2_WINDOW_UPDATE: + DEBUGF(LOG_CF(data, cf, "[h2sid=%u] recv WINDOW_UPDATE", stream_id)); + if((data_s->req.keepon & KEEP_SEND_HOLD) && + (data_s->req.keepon & KEEP_SEND)) { + data_s->req.keepon &= ~KEEP_SEND_HOLD; + drain_this(cf, data_s); + Curl_expire(data_s, 0, EXPIRE_RUN_NOW); + DEBUGF(LOG_CF(data, cf, "[h2sid=%u] un-holding after win update", + stream_id)); + } break; default: DEBUGF(LOG_CF(data_s, cf, "[h2sid=%u] recv frame %x", @@ -1006,18 +1031,6 @@ static int on_data_chunk_recv(nghttp2_session *session, uint8_t flags, return NGHTTP2_ERR_PAUSE; } -#if 0 - /* pause execution of nghttp2 if we received data for another handle - in order to process them first. */ - if(CF_DATA_CURRENT(cf) != data_s) { - ctx->pause_stream_id = stream_id; - DEBUGF(LOG_CF(data_s, cf, "[h2sid=%u] not call_data -> NGHTTP2_ERR_PAUSE", - stream_id)); - drain_this(cf, data_s); - return NGHTTP2_ERR_PAUSE; - } -#endif - return 0; } @@ -1030,44 +1043,43 @@ static int on_stream_close(nghttp2_session *session, int32_t stream_id, struct HTTP *stream; int rv; (void)session; - (void)stream_id; - if(stream_id) { - /* get the stream from the hash based on Stream ID, stream ID zero is for - connection-oriented stuff */ - data_s = nghttp2_session_get_stream_user_data(session, stream_id); - if(!data_s) { - /* We could get stream ID not in the hash. For example, if we - decided to reject stream (e.g., PUSH_PROMISE). */ - return 0; - } - DEBUGF(LOG_CF(data_s, cf, "[h2sid=%u] on_stream_close(), %s (err %d)", - stream_id, nghttp2_http2_strerror(error_code), error_code)); - stream = data_s->req.p.http; - if(!stream) - return NGHTTP2_ERR_CALLBACK_FAILURE; + /* get the stream from the hash based on Stream ID, stream ID zero is for + connection-oriented stuff */ + data_s = stream_id? + nghttp2_session_get_stream_user_data(session, stream_id) : NULL; + if(!data_s) { + return 0; + } + stream = data_s->req.p.http; + DEBUGF(LOG_CF(data_s, cf, "[h2sid=%u] on_stream_close(), %s (err %d)", + stream_id, nghttp2_http2_strerror(error_code), error_code)); + if(!stream) + return NGHTTP2_ERR_CALLBACK_FAILURE; - stream->closed = TRUE; - if(CF_DATA_CURRENT(cf) != data_s) { - drain_this(cf, data_s); - Curl_expire(data_s, 0, EXPIRE_RUN_NOW); - } - stream->error = error_code; + stream->closed = TRUE; + stream->error = error_code; + if(stream->error) + stream->reset = TRUE; - /* remove the entry from the hash as the stream is now gone */ - rv = nghttp2_session_set_stream_user_data(session, stream_id, 0); - if(rv) { - infof(data_s, "http/2: failed to clear user_data for stream %u", - stream_id); - DEBUGASSERT(0); - } - if(stream_id == ctx->pause_stream_id) { - DEBUGF(LOG_CF(data_s, cf, "[h2sid=%u] closed the pause stream", - stream_id)); - ctx->pause_stream_id = 0; - } - DEBUGF(LOG_CF(data_s, cf, "[h2sid=%u] closed, cleared", stream_id)); + if(CF_DATA_CURRENT(cf) != data_s) { + drain_this(cf, data_s); + Curl_expire(data_s, 0, EXPIRE_RUN_NOW); } + + /* remove `data_s` from the nghttp2 stream */ + rv = nghttp2_session_set_stream_user_data(session, stream_id, 0); + if(rv) { + infof(data_s, "http/2: failed to clear user_data for stream %u", + stream_id); + DEBUGASSERT(0); + } + if(stream_id == ctx->pause_stream_id) { + DEBUGF(LOG_CF(data_s, cf, "[h2sid=%u] closed the pause stream", + stream_id)); + ctx->pause_stream_id = 0; + } + DEBUGF(LOG_CF(data_s, cf, "[h2sid=%u] closed now", stream_id)); return 0; } @@ -1383,7 +1395,8 @@ static void http2_data_done(struct Curl_cfilter *cf, ctx->pause_stream_id = 0; } - if(premature || (!stream->closed && stream->stream_id)) { + (void)premature; + if(!stream->closed && stream->stream_id) { /* RST_STREAM */ DEBUGF(LOG_CF(data, cf, "[h2sid=%u] RST", stream->stream_id)); if(!nghttp2_submit_rst_stream(ctx->h2, NGHTTP2_FLAG_NONE, @@ -1446,15 +1459,6 @@ CURLcode Curl_http2_request_upgrade(struct dynbuf *req, } /* - * Returns nonzero if current HTTP/2 session should be closed. - */ -static int should_close_session(struct cf_h2_ctx *ctx) -{ - return ctx->drain_total == 0 && !nghttp2_session_want_read(ctx->h2) && - !nghttp2_session_want_write(ctx->h2); -} - -/* * h2_process_pending_input() processes pending input left in * httpc->inbuf. Then, call h2_session_send() to send pending data. * This function returns 0 if it succeeds, or -1 and error code will @@ -1586,8 +1590,6 @@ static ssize_t http2_handle_stream_close(struct Curl_cfilter *cf, } } - /* Reset to FALSE to prevent infinite loop in readwrite_data function. */ - stream->closed = FALSE; if(stream->error == NGHTTP2_REFUSED_STREAM) { DEBUGF(LOG_CF(data, cf, "[h2sid=%u] REFUSED_STREAM, try again on a new " "connection", stream->stream_id)); @@ -1603,6 +1605,11 @@ static ssize_t http2_handle_stream_close(struct Curl_cfilter *cf, *err = CURLE_HTTP2_STREAM; return -1; } + else if(stream->reset) { + failf(data, "HTTP/2 stream %u was reset", stream->stream_id); + *err = stream->bodystarted? CURLE_PARTIAL_FILE : CURLE_RECV_ERROR; + return -1; + } if(!stream->bodystarted) { failf(data, "HTTP/2 stream %u was closed cleanly, but before getting " @@ -1638,7 +1645,7 @@ static ssize_t http2_handle_stream_close(struct Curl_cfilter *cf, stream->close_handled = TRUE; - DEBUGF(LOG_CF(data, cf, "http2_recv returns 0, http2_handle_stream_close")); + DEBUGF(LOG_CF(data, cf, "[h2sid=%u] closed cleanly", stream->stream_id)); return 0; } @@ -1720,9 +1727,29 @@ static ssize_t cf_h2_recv(struct Curl_cfilter *cf, struct Curl_easy *data, struct HTTP *stream = data->req.p.http; ssize_t nread = -1; struct cf_call_data save; + bool conn_is_closed = FALSE; CF_DATA_SAVE(save, cf, data); + /* If the h2 session has told us to GOAWAY with an error AND + * indicated the highest stream id it has processes AND + * the stream we are trying to read has a higher id, this + * means we will most likely not receive any more for it. + * Treat this as if the server explicitly had RST the stream */ + if((ctx->goaway && ctx->goaway_error && + ctx->last_stream_id > 0 && + ctx->last_stream_id < stream->stream_id)) { + stream->reset = TRUE; + } + + /* If a stream is RST, it does not matter what state the h2 session + * is in, our answer to receiving data is always the same. */ + if(stream->reset) { + *err = stream->bodystarted? CURLE_PARTIAL_FILE : CURLE_RECV_ERROR; + nread = -1; + goto out; + } + if(should_close_session(ctx)) { DEBUGF(LOG_CF(data, cf, "http2_recv: nothing to do in this session")); if(cf->conn->bits.close) { @@ -1763,7 +1790,7 @@ static ssize_t cf_h2_recv(struct Curl_cfilter *cf, struct Curl_easy *data, goto out; } - DEBUGF(LOG_CF(data, cf, "[h2sid=%u] recv: win %u/%u", + DEBUGF(LOG_CF(data, cf, "[h2sid=%u] cf_recv: win %u/%u", stream->stream_id, nghttp2_session_get_local_window_size(ctx->h2), nghttp2_session_get_stream_local_window_size(ctx->h2, @@ -1846,57 +1873,40 @@ static ssize_t cf_h2_recv(struct Curl_cfilter *cf, struct Curl_easy *data, stream->memlen = 0; if(ctx->inbuflen > 0) { - DEBUGF(LOG_CF(data, cf, "Use data left in connection buffer, nread=%zd", - ctx->inbuflen - ctx->nread_inbuf)); + DEBUGF(LOG_CF(data, cf, "[h2sid=%u] %zd bytes in inbuf", + stream->stream_id, ctx->inbuflen - ctx->nread_inbuf)); if(h2_process_pending_input(cf, data, err)) return -1; } - while(stream->memlen == 0 /* have no data for this stream */ - && !ctx->pause_stream_id /* we are not paused either */ - && ctx->inbuflen == 0) { /* and out input buffer is empty */ + while(stream->memlen == 0 && /* have no data for this stream */ + !stream->closed && /* and it is not closed/reset */ + !ctx->pause_stream_id && /* we are not paused either */ + ctx->inbuflen == 0 && /* and out input buffer is empty */ + !conn_is_closed) { /* and connection is not closed */ /* Receive data from the "lower" filters */ nread = Curl_conn_cf_recv(cf->next, data, ctx->inbuf, H2_BUFSIZE, err); if(nread < 0) { - if(*err != CURLE_AGAIN) - failf(data, "Failed receiving HTTP2 data"); - else if(stream->closed) { - /* received when the stream was already closed! */ - nread = http2_handle_stream_close(cf, data, stream, err); - goto out; + DEBUGASSERT(*err); + if(*err == CURLE_AGAIN) { + break; } - - /* nothing to read from the lower layers, clear drain */ - drained_transfer(cf, data); - nread = -1; - goto out; + failf(data, "Failed receiving HTTP2 data"); + conn_is_closed = TRUE; } else if(nread == 0) { - if(!stream->closed) { - /* This will happen when the server or proxy server is SIGKILLed - during data transfer. We should emit an error since our data - received may be incomplete. */ - failf(data, "HTTP/2 stream %u was not closed cleanly before" - " end of the underlying stream", - stream->stream_id); - drained_transfer(cf, data); - *err = CURLE_PARTIAL_FILE; - nread = -1; - goto out; - } - - DEBUGF(LOG_CF(data, cf, "[h2sid=%u] end of stream", + DEBUGF(LOG_CF(data, cf, "[h2sid=%u] underlying connection is closed", stream->stream_id)); - *err = CURLE_OK; - nread = 0; - goto out; + conn_is_closed = TRUE; + } + else { + DEBUGF(LOG_CF(data, cf, "[h2sid=%u] read %zd from connection", + stream->stream_id, nread)); + ctx->inbuflen = nread; + DEBUGASSERT(ctx->nread_inbuf == 0); + if(h2_process_pending_input(cf, data, err)) + return -1; } - - DEBUGF(LOG_CF(data, cf, "read %zd from connection", nread)); - ctx->inbuflen = nread; - DEBUGASSERT(ctx->nread_inbuf == 0); - if(h2_process_pending_input(cf, data, err)) - return -1; } } @@ -1933,11 +1943,18 @@ static ssize_t cf_h2_recv(struct Curl_cfilter *cf, struct Curl_easy *data, *err = CURLE_OK; nread = retlen; - DEBUGF(LOG_CF(data, cf, "[h2sid=%u] cf_h2_recv -> %zd", - stream->stream_id, nread)); goto out; } + if(conn_is_closed && !stream->closed) { + /* underlying connection is closed and we have nothing for the stream. + * Treat this as a RST */ + stream->closed = stream->reset = TRUE; + failf(data, "HTTP/2 stream %u was not closed cleanly before" + " end of the underlying connection", + stream->stream_id); + } + if(stream->closed) { nread = http2_handle_stream_close(cf, data, stream, err); goto out; @@ -1950,9 +1967,9 @@ static ssize_t cf_h2_recv(struct Curl_cfilter *cf, struct Curl_easy *data, } *err = CURLE_AGAIN; nread = -1; - DEBUGF(LOG_CF(data, cf, "[h2sid=%u] recv -> AGAIN", - stream->stream_id)); out: + DEBUGF(LOG_CF(data, cf, "[h2sid=%u] cf_recv -> %zd, %d", + stream->stream_id, nread, *err)); CF_DATA_RESTORE(cf, save); return nread; } @@ -1976,19 +1993,20 @@ static ssize_t cf_h2_send(struct Curl_cfilter *cf, struct Curl_easy *data, CURLcode result; struct h2h3req *hreq; struct cf_call_data save; + ssize_t nwritten; CF_DATA_SAVE(save, cf, data); - DEBUGF(LOG_CF(data, cf, "send len=%zu", len)); + DEBUGF(LOG_CF(data, cf, "cf_send(len=%zu) start", len)); if(stream->stream_id != -1) { if(stream->close_handled) { infof(data, "stream %u closed", stream->stream_id); *err = CURLE_HTTP2_STREAM; - len = -1; + nwritten = -1; goto out; } else if(stream->closed) { - len = http2_handle_stream_close(cf, data, stream, err); + nwritten = http2_handle_stream_close(cf, data, stream, err); goto out; } /* If stream_id != -1, we have dispatched request HEADERS, and now @@ -1998,26 +2016,24 @@ static ssize_t cf_h2_send(struct Curl_cfilter *cf, struct Curl_easy *data, rv = nghttp2_session_resume_data(ctx->h2, stream->stream_id); if(nghttp2_is_fatal(rv)) { *err = CURLE_SEND_ERROR; - len = -1; + nwritten = -1; goto out; } result = h2_session_send(cf, data); if(result) { *err = result; - len = -1; + nwritten = -1; goto out; } - len -= stream->upload_len; - /* Nullify here because we call nghttp2_session_send() and they - might refer to the old buffer. */ + nwritten = (ssize_t)len - (ssize_t)stream->upload_len; stream->upload_mem = NULL; stream->upload_len = 0; if(should_close_session(ctx)) { DEBUGF(LOG_CF(data, cf, "send: nothing to do in this session")); *err = CURLE_HTTP2; - len = -1; + nwritten = -1; goto out; } @@ -2029,26 +2045,36 @@ static ssize_t cf_h2_send(struct Curl_cfilter *cf, struct Curl_easy *data, nghttp2_session_resume_data(ctx->h2, stream->stream_id); } -#ifdef DEBUG_HTTP2 - if(!len) { - infof(data, "http2_send: easy %p (stream %u) win %u/%u", - data, stream->stream_id, - nghttp2_session_get_remote_window_size(ctx->h2), - nghttp2_session_get_stream_remote_window_size(ctx->h2, - stream->stream_id) - ); - + if(!nwritten) { + size_t rwin = nghttp2_session_get_stream_remote_window_size(ctx->h2, + stream->stream_id); + DEBUGF(LOG_CF(data, cf, "[h2sid=%u] cf_send: win %u/%zu", + stream->stream_id, + nghttp2_session_get_remote_window_size(ctx->h2), rwin)); + if(rwin == 0) { + /* We cannot upload more as the stream's remote window size + * is 0. We need to receive WIN_UPDATEs before we can continue. + */ + data->req.keepon |= KEEP_SEND_HOLD; + DEBUGF(LOG_CF(data, cf, "[h2sid=%u] holding send as remote flow " + "window is exhausted", stream->stream_id)); + } } - infof(data, "http2_send returns %zu for stream %u", len, - stream->stream_id); -#endif + DEBUGF(LOG_CF(data, cf, "[h2sid=%u] cf_send returns %zd ", + stream->stream_id, nwritten)); + + /* handled writing BODY for open stream. */ goto out; } - + /* Stream has not been opened yet. `buf` is expected to contain + * request headers. */ + /* TODO: this assumes that the `buf` and `len` we are called with + * is *all* HEADERs and no body. We have no way to determine here + * if that is indeed the case. */ result = Curl_pseudo_headers(data, buf, len, NULL, &hreq); if(result) { *err = result; - len = -1; + nwritten = -1; goto out; } nheader = hreq->entries; @@ -2057,7 +2083,7 @@ static ssize_t cf_h2_send(struct Curl_cfilter *cf, struct Curl_easy *data, if(!nva) { Curl_pseudo_free(hreq); *err = CURLE_OUT_OF_MEMORY; - len = -1; + nwritten = -1; goto out; } else { @@ -2104,25 +2130,28 @@ static ssize_t cf_h2_send(struct Curl_cfilter *cf, struct Curl_easy *data, DEBUGF(LOG_CF(data, cf, "send: nghttp2_submit_request error (%s)%u", nghttp2_strerror(stream_id), stream_id)); *err = CURLE_SEND_ERROR; - len = -1; + nwritten = -1; goto out; } infof(data, "Using Stream ID: %u (easy handle %p)", stream_id, (void *)data); stream->stream_id = stream_id; + /* See TODO above. We assume that the whole buf was consumed by + * generating the request headers. */ + nwritten = len; result = h2_session_send(cf, data); if(result) { *err = result; - len = -1; + nwritten = -1; goto out; } if(should_close_session(ctx)) { DEBUGF(LOG_CF(data, cf, "send: nothing to do in this session")); *err = CURLE_HTTP2; - len = -1; + nwritten = -1; goto out; } @@ -2137,7 +2166,7 @@ static ssize_t cf_h2_send(struct Curl_cfilter *cf, struct Curl_easy *data, out: CF_DATA_RESTORE(cf, save); - return len; + return nwritten; } static int cf_h2_get_select_socks(struct Curl_cfilter *cf, @@ -2160,7 +2189,7 @@ static int cf_h2_get_select_socks(struct Curl_cfilter *cf, /* we're (still uploading OR the HTTP/2 layer wants to send data) AND there's a window to send data in */ - if((((k->keepon & (KEEP_SEND|KEEP_SEND_PAUSE)) == KEEP_SEND) || + if((((k->keepon & KEEP_SENDBITS) == KEEP_SEND) || nghttp2_session_want_write(ctx->h2)) && (nghttp2_session_get_remote_window_size(ctx->h2) && nghttp2_session_get_stream_remote_window_size(ctx->h2, @@ -2329,14 +2358,17 @@ static bool cf_h2_data_pending(struct Curl_cfilter *cf, } static bool cf_h2_is_alive(struct Curl_cfilter *cf, - struct Curl_easy *data) + struct Curl_easy *data, + bool *input_pending) { struct cf_h2_ctx *ctx = cf->ctx; CURLcode result; struct cf_call_data save; CF_DATA_SAVE(save, cf, data); - result = (ctx && ctx->h2 && !http2_connisdead(cf, data)); + result = (ctx && ctx->h2 && http2_connisalive(cf, data, input_pending)); + DEBUGF(LOG_CF(data, cf, "conn alive -> %d, input_pending=%d", + result, *input_pending)); CF_DATA_RESTORE(cf, save); return result; } @@ -2479,7 +2511,8 @@ bool Curl_http2_may_switch(struct Curl_easy *data, int sockindex) { (void)sockindex; - if(data->state.httpwant == CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE) { + if(!Curl_conn_is_http2(data, conn, sockindex) && + data->state.httpwant == CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE) { #ifndef CURL_DISABLE_PROXY if(conn->bits.httpproxy && !conn->bits.tunnel_proxy) { /* We don't support HTTP/2 proxies yet. Also it's debatable diff --git a/Utilities/cmcurl/lib/http_aws_sigv4.c b/Utilities/cmcurl/lib/http_aws_sigv4.c index f8ce169..7d50cff 100644 --- a/Utilities/cmcurl/lib/http_aws_sigv4.c +++ b/Utilities/cmcurl/lib/http_aws_sigv4.c @@ -58,13 +58,15 @@ #define TIMESTAMP_SIZE 17 -static void sha256_to_hex(char *dst, unsigned char *sha, size_t dst_l) +/* hex-encoded with trailing null */ +#define SHA256_HEX_LENGTH (2 * SHA256_DIGEST_LENGTH + 1) + +static void sha256_to_hex(char *dst, unsigned char *sha) { int i; - DEBUGASSERT(dst_l >= 65); - for(i = 0; i < 32; ++i) { - msnprintf(dst + (i * 2), dst_l - (i * 2), "%02x", sha[i]); + for(i = 0; i < SHA256_DIGEST_LENGTH; ++i) { + msnprintf(dst + (i * 2), SHA256_HEX_LENGTH - (i * 2), "%02x", sha[i]); } } @@ -135,6 +137,7 @@ static CURLcode make_headers(struct Curl_easy *data, char *timestamp, char *provider1, char **date_header, + char *content_sha256_header, struct dynbuf *canonical_headers, struct dynbuf *signed_headers) { @@ -189,6 +192,13 @@ static CURLcode make_headers(struct Curl_easy *data, } + if (*content_sha256_header) { + tmp_head = curl_slist_append(head, content_sha256_header); + if(!tmp_head) + goto fail; + head = tmp_head; + } + for(l = data->set.headers; l; l = l->next) { tmp_head = curl_slist_append(head, l->data); if(!tmp_head) @@ -267,6 +277,9 @@ fail: } #define CONTENT_SHA256_KEY_LEN (MAX_SIGV4_LEN + sizeof("X--Content-Sha256")) +/* add 2 for ": " between header name and value */ +#define CONTENT_SHA256_HDR_LEN (CONTENT_SHA256_KEY_LEN + 2 + \ + SHA256_HEX_LENGTH) /* try to parse a payload hash from the content-sha256 header */ static char *parse_content_sha_hdr(struct Curl_easy *data, @@ -300,6 +313,63 @@ static char *parse_content_sha_hdr(struct Curl_easy *data, return value; } +static CURLcode calc_payload_hash(struct Curl_easy *data, + unsigned char *sha_hash, char *sha_hex) +{ + const char *post_data = data->set.postfields; + size_t post_data_len = 0; + CURLcode result; + + if(post_data) { + if(data->set.postfieldsize < 0) + post_data_len = strlen(post_data); + else + post_data_len = (size_t)data->set.postfieldsize; + } + result = Curl_sha256it(sha_hash, (const unsigned char *) post_data, + post_data_len); + if(!result) + sha256_to_hex(sha_hex, sha_hash); + return result; +} + +#define S3_UNSIGNED_PAYLOAD "UNSIGNED-PAYLOAD" + +static CURLcode calc_s3_payload_hash(struct Curl_easy *data, + Curl_HttpReq httpreq, char *provider1, + unsigned char *sha_hash, + char *sha_hex, char *header) +{ + bool empty_method = (httpreq == HTTPREQ_GET || httpreq == HTTPREQ_HEAD); + /* The request method or filesize indicate no request payload */ + bool empty_payload = (empty_method || data->set.filesize == 0); + /* The POST payload is in memory */ + bool post_payload = (httpreq == HTTPREQ_POST && data->set.postfields); + CURLcode ret = CURLE_OUT_OF_MEMORY; + + if(empty_payload || post_payload) { + /* Calculate a real hash when we know the request payload */ + ret = calc_payload_hash(data, sha_hash, sha_hex); + if(ret) + goto fail; + } + else { + /* Fall back to s3's UNSIGNED-PAYLOAD */ + size_t len = sizeof(S3_UNSIGNED_PAYLOAD) - 1; + DEBUGASSERT(len < SHA256_HEX_LENGTH); /* 16 < 65 */ + memcpy(sha_hex, S3_UNSIGNED_PAYLOAD, len); + sha_hex[len] = 0; + } + + /* format the required content-sha256 header */ + msnprintf(header, CONTENT_SHA256_HDR_LEN, + "x-%s-content-sha256: %s", provider1, sha_hex); + + ret = CURLE_OK; +fail: + return ret; +} + CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy) { CURLcode ret = CURLE_OUT_OF_MEMORY; @@ -310,6 +380,7 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy) char provider1[MAX_SIGV4_LEN + 1]=""; char region[MAX_SIGV4_LEN + 1]=""; char service[MAX_SIGV4_LEN + 1]=""; + bool sign_as_s3 = false; const char *hostname = conn->host.name; time_t clock; struct tm tm; @@ -318,20 +389,21 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy) struct dynbuf canonical_headers; struct dynbuf signed_headers; char *date_header = NULL; + Curl_HttpReq httpreq; + const char *method = NULL; char *payload_hash = NULL; size_t payload_hash_len = 0; - const char *post_data = data->set.postfields; - size_t post_data_len = 0; - unsigned char sha_hash[32]; - char sha_hex[65]; + unsigned char sha_hash[SHA256_DIGEST_LENGTH]; + char sha_hex[SHA256_HEX_LENGTH]; + char content_sha256_hdr[CONTENT_SHA256_HDR_LEN + 2] = ""; /* add \r\n */ char *canonical_request = NULL; char *request_type = NULL; char *credential_scope = NULL; char *str_to_sign = NULL; const char *user = data->state.aptr.user ? data->state.aptr.user : ""; char *secret = NULL; - unsigned char sign0[32] = {0}; - unsigned char sign1[32] = {0}; + unsigned char sign0[SHA256_DIGEST_LENGTH] = {0}; + unsigned char sign1[SHA256_DIGEST_LENGTH] = {0}; char *auth_headers = NULL; DEBUGASSERT(!proxy); @@ -408,6 +480,29 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy) } } + Curl_http_method(data, conn, &method, &httpreq); + + /* AWS S3 requires a x-amz-content-sha256 header, and supports special + * values like UNSIGNED-PAYLOAD */ + sign_as_s3 = (strcasecompare(provider0, "aws") && + strcasecompare(service, "s3")); + + payload_hash = parse_content_sha_hdr(data, provider1, &payload_hash_len); + + if(!payload_hash) { + if(sign_as_s3) + ret = calc_s3_payload_hash(data, httpreq, provider1, sha_hash, + sha_hex, content_sha256_hdr); + else + ret = calc_payload_hash(data, sha_hash, sha_hex); + if(ret) + goto fail; + + payload_hash = sha_hex; + /* may be shorter than SHA256_HEX_LENGTH, like S3_UNSIGNED_PAYLOAD */ + payload_hash_len = strlen(sha_hex); + } + #ifdef DEBUGBUILD { char *force_timestamp = getenv("CURL_FORCETIME"); @@ -429,54 +524,37 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy) } ret = make_headers(data, hostname, timestamp, provider1, - &date_header, &canonical_headers, &signed_headers); + &date_header, content_sha256_hdr, + &canonical_headers, &signed_headers); if(ret) goto fail; ret = CURLE_OUT_OF_MEMORY; + if(*content_sha256_hdr) { + /* make_headers() needed this without the \r\n for canonicalization */ + size_t hdrlen = strlen(content_sha256_hdr); + DEBUGASSERT(hdrlen + 3 < sizeof(content_sha256_hdr)); + memcpy(content_sha256_hdr + hdrlen, "\r\n", 3); + } + memcpy(date, timestamp, sizeof(date)); date[sizeof(date) - 1] = 0; - payload_hash = parse_content_sha_hdr(data, provider1, &payload_hash_len); - - if(!payload_hash) { - if(post_data) { - if(data->set.postfieldsize < 0) - post_data_len = strlen(post_data); - else - post_data_len = (size_t)data->set.postfieldsize; - } - if(Curl_sha256it(sha_hash, (const unsigned char *) post_data, - post_data_len)) - goto fail; - - sha256_to_hex(sha_hex, sha_hash, sizeof(sha_hex)); - payload_hash = sha_hex; - payload_hash_len = strlen(sha_hex); - } - - { - Curl_HttpReq httpreq; - const char *method; - - Curl_http_method(data, conn, &method, &httpreq); - - canonical_request = - curl_maprintf("%s\n" /* HTTPRequestMethod */ - "%s\n" /* CanonicalURI */ - "%s\n" /* CanonicalQueryString */ - "%s\n" /* CanonicalHeaders */ - "%s\n" /* SignedHeaders */ - "%.*s", /* HashedRequestPayload in hex */ - method, - data->state.up.path, - data->state.up.query ? data->state.up.query : "", - Curl_dyn_ptr(&canonical_headers), - Curl_dyn_ptr(&signed_headers), - (int)payload_hash_len, payload_hash); - if(!canonical_request) - goto fail; - } + canonical_request = + curl_maprintf("%s\n" /* HTTPRequestMethod */ + "%s\n" /* CanonicalURI */ + "%s\n" /* CanonicalQueryString */ + "%s\n" /* CanonicalHeaders */ + "%s\n" /* SignedHeaders */ + "%.*s", /* HashedRequestPayload in hex */ + method, + data->state.up.path, + data->state.up.query ? data->state.up.query : "", + Curl_dyn_ptr(&canonical_headers), + Curl_dyn_ptr(&signed_headers), + (int)payload_hash_len, payload_hash); + if(!canonical_request) + goto fail; /* provider 0 lowercase */ Curl_strntolower(provider0, provider0, strlen(provider0)); @@ -493,7 +571,7 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy) strlen(canonical_request))) goto fail; - sha256_to_hex(sha_hex, sha_hash, sizeof(sha_hex)); + sha256_to_hex(sha_hex, sha_hash); /* provider 0 uppercase */ Curl_strntoupper(provider0, provider0, strlen(provider0)); @@ -527,20 +605,22 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy) HMAC_SHA256(sign0, sizeof(sign0), request_type, strlen(request_type), sign1); HMAC_SHA256(sign1, sizeof(sign1), str_to_sign, strlen(str_to_sign), sign0); - sha256_to_hex(sha_hex, sign0, sizeof(sha_hex)); + sha256_to_hex(sha_hex, sign0); /* provider 0 uppercase */ auth_headers = curl_maprintf("Authorization: %s4-HMAC-SHA256 " "Credential=%s/%s, " "SignedHeaders=%s, " "Signature=%s\r\n" - "%s\r\n", + "%s\r\n" + "%s", /* optional sha256 header includes \r\n */ provider0, user, credential_scope, Curl_dyn_ptr(&signed_headers), sha_hex, - date_header); + date_header, + content_sha256_hdr); if(!auth_headers) { goto fail; } diff --git a/Utilities/cmcurl/lib/http_proxy.c b/Utilities/cmcurl/lib/http_proxy.c index fdd092d..9f214a3 100644 --- a/Utilities/cmcurl/lib/http_proxy.c +++ b/Utilities/cmcurl/lib/http_proxy.c @@ -403,7 +403,6 @@ static CURLcode on_resp_header(struct Curl_cfilter *cf, { CURLcode result = CURLE_OK; struct SingleRequest *k = &data->req; - int subversion = 0; (void)cf; if((checkprefix("WWW-Authenticate:", header) && @@ -461,11 +460,14 @@ static CURLcode on_resp_header(struct Curl_cfilter *cf, STRCONST("Proxy-Connection:"), STRCONST("close"))) ts->close_connection = TRUE; - else if(2 == sscanf(header, "HTTP/1.%d %d", - &subversion, - &k->httpcode)) { + else if(!strncmp(header, "HTTP/1.", 7) && + ((header[7] == '0') || (header[7] == '1')) && + (header[8] == ' ') && + ISDIGIT(header[9]) && ISDIGIT(header[10]) && ISDIGIT(header[11]) && + !ISDIGIT(header[12])) { /* store the HTTP code from the proxy */ - data->info.httpproxycode = k->httpcode; + data->info.httpproxycode = k->httpcode = (header[9] - '0') * 100 + + (header[10] - '0') * 10 + (header[11] - '0'); } return result; } diff --git a/Utilities/cmcurl/lib/idn.c b/Utilities/cmcurl/lib/idn.c index abba895..5f4b07e 100644 --- a/Utilities/cmcurl/lib/idn.c +++ b/Utilities/cmcurl/lib/idn.c @@ -184,6 +184,11 @@ CURLcode Curl_idnconvert_hostname(struct hostname *host) if(!Curl_is_ASCII_name(host->name)) { char *decoded = idn_decode(host->name); if(decoded) { + if(!*decoded) { + /* zero length is a bad host name */ + Curl_idn_free(decoded); + return CURLE_URL_MALFORMAT; + } /* successful */ host->encalloc = decoded; /* change the name pointer to point to the encoded hostname */ diff --git a/Utilities/cmcurl/lib/inet_ntop.c b/Utilities/cmcurl/lib/inet_ntop.c index 024f8da..770ed3a 100644 --- a/Utilities/cmcurl/lib/inet_ntop.c +++ b/Utilities/cmcurl/lib/inet_ntop.c @@ -42,6 +42,15 @@ #define INT16SZ 2 /* + * If ENABLE_IPV6 is disabled, we still want to parse IPv6 addresses, so make + * sure we have _some_ value for AF_INET6 without polluting our fake value + * everywhere. + */ +#if !defined(ENABLE_IPV6) && !defined(AF_INET6) +#define AF_INET6 (AF_INET + 1) +#endif + +/* * Format an IPv4 address, more or less like inet_ntop(). * * Returns `dst' (as a const) @@ -72,7 +81,6 @@ static char *inet_ntop4 (const unsigned char *src, char *dst, size_t size) return dst; } -#ifdef ENABLE_IPV6 /* * Convert IPv6 binary address into presentation (printable) format. */ @@ -168,7 +176,6 @@ static char *inet_ntop6 (const unsigned char *src, char *dst, size_t size) strcpy(dst, tmp); return dst; } -#endif /* ENABLE_IPV6 */ /* * Convert a network format address to presentation format. @@ -187,10 +194,8 @@ char *Curl_inet_ntop(int af, const void *src, char *buf, size_t size) switch(af) { case AF_INET: return inet_ntop4((const unsigned char *)src, buf, size); -#ifdef ENABLE_IPV6 case AF_INET6: return inet_ntop6((const unsigned char *)src, buf, size); -#endif default: errno = EAFNOSUPPORT; return NULL; diff --git a/Utilities/cmcurl/lib/inet_pton.c b/Utilities/cmcurl/lib/inet_pton.c index f2e17b8..7d3c698 100644 --- a/Utilities/cmcurl/lib/inet_pton.c +++ b/Utilities/cmcurl/lib/inet_pton.c @@ -39,14 +39,21 @@ #define INT16SZ 2 /* + * If ENABLE_IPV6 is disabled, we still want to parse IPv6 addresses, so make + * sure we have _some_ value for AF_INET6 without polluting our fake value + * everywhere. + */ +#if !defined(ENABLE_IPV6) && !defined(AF_INET6) +#define AF_INET6 (AF_INET + 1) +#endif + +/* * WARNING: Don't even consider trying to compile this on a system where * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX. */ static int inet_pton4(const char *src, unsigned char *dst); -#ifdef ENABLE_IPV6 static int inet_pton6(const char *src, unsigned char *dst); -#endif /* int * inet_pton(af, src, dst) @@ -70,10 +77,8 @@ Curl_inet_pton(int af, const char *src, void *dst) switch(af) { case AF_INET: return (inet_pton4(src, (unsigned char *)dst)); -#ifdef ENABLE_IPV6 case AF_INET6: return (inet_pton6(src, (unsigned char *)dst)); -#endif default: errno = EAFNOSUPPORT; return (-1); @@ -135,7 +140,6 @@ inet_pton4(const char *src, unsigned char *dst) return (1); } -#ifdef ENABLE_IPV6 /* int * inet_pton6(src, dst) * convert presentation level address to network order binary form. @@ -234,6 +238,5 @@ inet_pton6(const char *src, unsigned char *dst) memcpy(dst, tmp, IN6ADDRSZ); return (1); } -#endif /* ENABLE_IPV6 */ #endif /* HAVE_INET_PTON */ diff --git a/Utilities/cmcurl/lib/krb5.c b/Utilities/cmcurl/lib/krb5.c index 3cd64e1..a71779a 100644 --- a/Utilities/cmcurl/lib/krb5.c +++ b/Utilities/cmcurl/lib/krb5.c @@ -721,8 +721,7 @@ int Curl_sec_read_msg(struct Curl_easy *data, struct connectdata *conn, return 0; if(buf[3] != '-') - /* safe to ignore return code */ - (void)sscanf(buf, "%d", &ret_code); + ret_code = atoi(buf); if(buf[decoded_len - 1] == '\n') buf[decoded_len - 1] = '\0'; @@ -765,8 +764,9 @@ static int sec_set_protection_level(struct Curl_easy *data) pbsz = strstr(data->state.buffer, "PBSZ="); if(pbsz) { - /* ignore return code, use default value if it fails */ - (void)sscanf(pbsz, "PBSZ=%u", &buffer_size); + /* stick to default value if the check fails */ + if(!strncmp(pbsz, "PBSZ=", 5) && ISDIGIT(pbsz[5])) + buffer_size = atoi(&pbsz[5]); if(buffer_size < conn->buffer_size) conn->buffer_size = buffer_size; } diff --git a/Utilities/cmcurl/lib/ldap.c b/Utilities/cmcurl/lib/ldap.c index 5e53f4c..595e4b3 100644 --- a/Utilities/cmcurl/lib/ldap.c +++ b/Utilities/cmcurl/lib/ldap.c @@ -140,6 +140,14 @@ static void _ldap_free_urldesc(LDAPURLDesc *ludp); #define ldap_err2string ldap_err2stringA #endif +#if defined(USE_WIN32_LDAP) && defined(_MSC_VER) && (_MSC_VER <= 1600) +/* Workaround for warning: + 'type cast' : conversion from 'int' to 'void *' of greater size */ +#undef LDAP_OPT_ON +#undef LDAP_OPT_OFF +#define LDAP_OPT_ON ((void *)(size_t)1) +#define LDAP_OPT_OFF ((void *)(size_t)0) +#endif static CURLcode ldap_do(struct Curl_easy *data, bool *done); diff --git a/Utilities/cmcurl/lib/mqtt.c b/Utilities/cmcurl/lib/mqtt.c index 0b54bc0..47af369 100644 --- a/Utilities/cmcurl/lib/mqtt.c +++ b/Utilities/cmcurl/lib/mqtt.c @@ -122,8 +122,9 @@ static CURLcode mqtt_send(struct Curl_easy *data, struct MQTT *mq = data->req.p.mqtt; ssize_t n; result = Curl_write(data, sockfd, buf, len, &n); - if(!result) - Curl_debug(data, CURLINFO_HEADER_OUT, buf, (size_t)n); + if(result) + return result; + Curl_debug(data, CURLINFO_HEADER_OUT, buf, (size_t)n); if(len != (size_t)n) { size_t nsend = len - n; char *sendleftovers = Curl_memdup(&buf[n], nsend); diff --git a/Utilities/cmcurl/lib/multi.c b/Utilities/cmcurl/lib/multi.c index f020a0b..731b259 100644 --- a/Utilities/cmcurl/lib/multi.c +++ b/Utilities/cmcurl/lib/multi.c @@ -445,9 +445,6 @@ struct Curl_multi *Curl_multi_handle(int hashsize, /* socket hash */ sockhash_destroy(&multi->sockhash); Curl_hash_destroy(&multi->hostcache); Curl_conncache_destroy(&multi->conn_cache); - Curl_llist_destroy(&multi->msglist, NULL); - Curl_llist_destroy(&multi->pending, NULL); - free(multi); return NULL; } @@ -459,6 +456,42 @@ struct Curl_multi *curl_multi_init(void) CURL_DNS_HASH_SIZE); } +static void link_easy(struct Curl_multi *multi, + struct Curl_easy *data) +{ + /* We add the new easy entry last in the list. */ + data->next = NULL; /* end of the line */ + if(multi->easyp) { + struct Curl_easy *last = multi->easylp; + last->next = data; + data->prev = last; + multi->easylp = data; /* the new last node */ + } + else { + /* first node, make prev NULL! */ + data->prev = NULL; + multi->easylp = multi->easyp = data; /* both first and last */ + } +} + +/* unlink the given easy handle from the linked list of easy handles */ +static void unlink_easy(struct Curl_multi *multi, + struct Curl_easy *data) +{ + /* make the previous node point to our next */ + if(data->prev) + data->prev->next = data->next; + else + multi->easyp = data->next; /* point to first node */ + + /* make our next point to our previous node */ + if(data->next) + data->next->prev = data->prev; + else + multi->easylp = data->prev; /* point to last node */ +} + + CURLMcode curl_multi_add_handle(struct Curl_multi *multi, struct Curl_easy *data) { @@ -554,19 +587,7 @@ CURLMcode curl_multi_add_handle(struct Curl_multi *multi, data->psl = &multi->psl; #endif - /* We add the new entry last in the list. */ - data->next = NULL; /* end of the line */ - if(multi->easyp) { - struct Curl_easy *last = multi->easylp; - last->next = data; - data->prev = last; - multi->easylp = data; /* the new last node */ - } - else { - /* first node, make prev NULL! */ - data->prev = NULL; - multi->easylp = multi->easyp = data; /* both first and last */ - } + link_easy(multi, data); /* increase the node-counter */ multi->num_easy++; @@ -841,10 +862,6 @@ CURLMcode curl_multi_remove_handle(struct Curl_multi *multi, Curl_wildcard_dtor(&data->wildcard); - /* destroy the timeout list that is held in the easy handle, do this *after* - multi_done() as that may actually call Curl_expire that uses this */ - Curl_llist_destroy(&data->state.timeoutlist, NULL); - /* change state without using multistate(), only to make singlesocket() do what we want */ data->mstate = MSTATE_COMPLETED; @@ -917,17 +934,7 @@ CURLMcode curl_multi_remove_handle(struct Curl_multi *multi, } } - /* make the previous node point to our next */ - if(data->prev) - data->prev->next = data->next; - else - multi->easyp = data->next; /* point to first node */ - - /* make our next point to our previous node */ - if(data->next) - data->next->prev = data->prev; - else - multi->easylp = data->prev; /* point to last node */ + unlink_easy(multi, data); /* NOTE NOTE NOTE We do not touch the easy handle here! */ @@ -976,7 +983,7 @@ void Curl_attach_connection(struct Curl_easy *data, data->conn = conn; Curl_llist_insert_next(&conn->easyq, conn->easyq.tail, data, &data->conn_queue); - if(conn->handler->attach) + if(conn->handler && conn->handler->attach) conn->handler->attach(data, conn); Curl_conn_ev_data_attach(conn, data); } @@ -2192,7 +2199,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, #ifndef CURL_DISABLE_FTP /* some steps needed for wildcard matching */ if(data->state.wildcardmatch) { - struct WildcardData *wc = &data->wildcard; + struct WildcardData *wc = data->wildcard; if(wc->state == CURLWC_DONE || wc->state == CURLWC_SKIP) { /* skip some states if it is important */ multi_done(data, CURLE_OK, FALSE); @@ -2344,7 +2351,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, #ifndef CURL_DISABLE_FTP if(data->state.wildcardmatch && ((data->conn->handler->flags & PROTOPT_WILDCARD) == 0)) { - data->wildcard.state = CURLWC_DONE; + data->wildcard->state = CURLWC_DONE; } #endif multistate(data, MSTATE_DONE); @@ -2574,7 +2581,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, #ifndef CURL_DISABLE_FTP if(data->state.wildcardmatch) { - if(data->wildcard.state != CURLWC_DONE) { + if(data->wildcard->state != CURLWC_DONE) { /* if a wildcard is set and we are not ending -> lets start again with MSTATE_INIT */ multistate(data, MSTATE_INIT); @@ -2706,18 +2713,25 @@ CURLMcode curl_multi_perform(struct Curl_multi *multi, int *running_handles) return CURLM_RECURSIVE_API_CALL; data = multi->easyp; - while(data) { + if(data) { CURLMcode result; + bool nosig = data->set.no_signal; SIGPIPE_VARIABLE(pipe_st); - sigpipe_ignore(data, &pipe_st); - result = multi_runsingle(multi, &now, data); + /* Do the loop and only alter the signal ignore state if the next handle + has a different NO_SIGNAL state than the previous */ + do { + if(data->set.no_signal != nosig) { + sigpipe_restore(&pipe_st); + sigpipe_ignore(data, &pipe_st); + nosig = data->set.no_signal; + } + result = multi_runsingle(multi, &now, data); + if(result) + returncode = result; + data = data->next; /* operate on next handle */ + } while(data); sigpipe_restore(&pipe_st); - - if(result) - returncode = result; - - data = data->next; /* operate on next handle */ } /* @@ -2788,9 +2802,6 @@ CURLMcode curl_multi_cleanup(struct Curl_multi *multi) sockhash_destroy(&multi->sockhash); Curl_conncache_destroy(&multi->conn_cache); - Curl_llist_destroy(&multi->msglist, NULL); - Curl_llist_destroy(&multi->pending, NULL); - Curl_hash_destroy(&multi->hostcache); Curl_psl_destroy(&multi->psl); diff --git a/Utilities/cmcurl/lib/parsedate.c b/Utilities/cmcurl/lib/parsedate.c index 82ac1d8..1662dd3 100644 --- a/Utilities/cmcurl/lib/parsedate.c +++ b/Utilities/cmcurl/lib/parsedate.c @@ -212,56 +212,55 @@ static int checkday(const char *check, size_t len) { int i; const char * const *what; - bool found = FALSE; if(len > 3) what = &weekday[0]; - else + else if(len == 3) what = &Curl_wkday[0]; + else + return -1; /* too short */ for(i = 0; i<7; i++) { - if(strcasecompare(check, what[0])) { - found = TRUE; - break; - } + size_t ilen = strlen(what[0]); + if((ilen == len) && + strncasecompare(check, what[0], len)) + return i; what++; } - return found?i:-1; + return -1; } -static int checkmonth(const char *check) +static int checkmonth(const char *check, size_t len) { int i; - const char * const *what; - bool found = FALSE; + const char * const *what = &Curl_month[0]; + if(len != 3) + return -1; /* not a month */ - what = &Curl_month[0]; for(i = 0; i<12; i++) { - if(strcasecompare(check, what[0])) { - found = TRUE; - break; - } + if(strncasecompare(check, what[0], 3)) + return i; what++; } - return found?i:-1; /* return the offset or -1, no real offset is -1 */ + return -1; /* return the offset or -1, no real offset is -1 */ } /* return the time zone offset between GMT and the input one, in number of seconds or -1 if the timezone wasn't found/legal */ -static int checktz(const char *check) +static int checktz(const char *check, size_t len) { unsigned int i; - const struct tzinfo *what; - bool found = FALSE; + const struct tzinfo *what = tz; + if(len > 4) /* longer than any valid timezone */ + return -1; - what = tz; for(i = 0; i< sizeof(tz)/sizeof(tz[0]); i++) { - if(strcasecompare(check, what->name)) { - found = TRUE; - break; - } + size_t ilen = strlen(what->name); + if((ilen == len) && + strncasecompare(check, what->name, len)) + return what->offset*60; what++; } - return found?what->offset*60:-1; + return -1; } static void skip(const char **date) @@ -294,6 +293,53 @@ static time_t time2epoch(int sec, int min, int hour, + hour) * 60 + min) * 60 + sec; } +/* Returns the value of a single-digit or two-digit decimal number, return + then pointer to after the number. The 'date' pointer is known to point to a + digit. */ +static int oneortwodigit(const char *date, const char **endp) +{ + int num = date[0] - '0'; + if(ISDIGIT(date[1])) { + *endp = &date[2]; + return num*10 + (date[1] - '0'); + } + *endp = &date[1]; + return num; +} + + +/* HH:MM:SS or HH:MM and accept single-digits too */ +static bool match_time(const char *date, + int *h, int *m, int *s, char **endp) +{ + const char *p; + int hh, mm, ss = 0; + hh = oneortwodigit(date, &p); + if((hh < 24) && (*p == ':') && ISDIGIT(p[1])) { + mm = oneortwodigit(&p[1], &p); + if(mm < 60) { + if((*p == ':') && ISDIGIT(p[1])) { + ss = oneortwodigit(&p[1], &p); + if(ss <= 60) { + /* valid HH:MM:SS */ + goto match; + } + } + else { + /* valid HH:MM */ + goto match; + } + } + } + return FALSE; /* not a time string */ + match: + *h = hh; + *m = mm; + *s = ss; + *endp = (char *)p; + return TRUE; +} + /* * parsedate() * @@ -305,6 +351,9 @@ static time_t time2epoch(int sec, int min, int hour, * PARSEDATE_SOONER - time underflow at the low end of time_t */ +/* Wednesday is the longest name this parser knows about */ +#define NAME_LEN 12 + static int parsedate(const char *date, time_t *output) { time_t t = 0; @@ -327,32 +376,32 @@ static int parsedate(const char *date, time_t *output) if(ISALPHA(*date)) { /* a name coming up */ - char buf[32]=""; - size_t len; - if(sscanf(date, "%31[ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz]", buf)) - len = strlen(buf); - else - len = 0; - - if(wdaynum == -1) { - wdaynum = checkday(buf, len); - if(wdaynum != -1) - found = TRUE; - } - if(!found && (monnum == -1)) { - monnum = checkmonth(buf); - if(monnum != -1) - found = TRUE; + size_t len = 0; + const char *p = date; + while(ISALPHA(*p) && (len < NAME_LEN)) { + p++; + len++; } - if(!found && (tzoff == -1)) { - /* this just must be a time zone string */ - tzoff = checktz(buf); - if(tzoff != -1) - found = TRUE; - } + if(len != NAME_LEN) { + if(wdaynum == -1) { + wdaynum = checkday(date, len); + if(wdaynum != -1) + found = TRUE; + } + if(!found && (monnum == -1)) { + monnum = checkmonth(date, len); + if(monnum != -1) + found = TRUE; + } + if(!found && (tzoff == -1)) { + /* this just must be a time zone string */ + tzoff = checktz(date, len); + if(tzoff != -1) + found = TRUE; + } + } if(!found) return PARSEDATE_FAIL; /* bad string */ @@ -362,18 +411,10 @@ static int parsedate(const char *date, time_t *output) /* a digit */ int val; char *end; - int len = 0; if((secnum == -1) && - (3 == sscanf(date, "%02d:%02d:%02d%n", - &hournum, &minnum, &secnum, &len))) { - /* time stamp! */ - date += len; - } - else if((secnum == -1) && - (2 == sscanf(date, "%02d:%02d%n", &hournum, &minnum, &len))) { - /* time stamp without seconds */ - date += len; - secnum = 0; + match_time(date, &hournum, &minnum, &secnum, &end)) { + /* time stamp */ + date = end; } else { long lval; diff --git a/Utilities/cmcurl/lib/progress.c b/Utilities/cmcurl/lib/progress.c index a222888..6092b78 100644 --- a/Utilities/cmcurl/lib/progress.c +++ b/Utilities/cmcurl/lib/progress.c @@ -87,8 +87,6 @@ static char *max5data(curl_off_t bytes, char *max5) CURL_FORMAT_CURL_OFF_T "M", bytes/ONE_MEGABYTE, (bytes%ONE_MEGABYTE) / (ONE_MEGABYTE/CURL_OFF_T_C(10)) ); -#if (SIZEOF_CURL_OFF_T > 4) - else if(bytes < CURL_OFF_T_C(10000) * ONE_MEGABYTE) /* 'XXXXM' is good until we're at 10000MB or above */ msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "M", bytes/ONE_MEGABYTE); @@ -111,15 +109,8 @@ static char *max5data(curl_off_t bytes, char *max5) /* up to 10000PB, display without decimal: XXXXP */ msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "P", bytes/ONE_PETABYTE); - /* 16384 petabytes (16 exabytes) is the maximum a 64 bit unsigned number - can hold, but our data type is signed so 8192PB will be the maximum. */ - -#else - - else - msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "M", bytes/ONE_MEGABYTE); - -#endif + /* 16384 petabytes (16 exabytes) is the maximum a 64 bit unsigned number can + hold, but our data type is signed so 8192PB will be the maximum. */ return max5; } diff --git a/Utilities/cmcurl/lib/rand.c b/Utilities/cmcurl/lib/rand.c index 4b6ac07..9abb722 100644 --- a/Utilities/cmcurl/lib/rand.c +++ b/Utilities/cmcurl/lib/rand.c @@ -30,6 +30,10 @@ #ifdef HAVE_ARPA_INET_H #include <arpa/inet.h> #endif +#ifdef HAVE_ARC4RANDOM +/* Some platforms might have the prototype missing (ubuntu + libressl) */ +uint32_t arc4random(void); +#endif #include <curl/curl.h> #include "vtls/vtls.h" @@ -143,6 +147,11 @@ static CURLcode randit(struct Curl_easy *data, unsigned int *rnd) } #endif +#ifdef HAVE_ARC4RANDOM + *rnd = (unsigned int)arc4random(); + return CURLE_OK; +#endif + #if defined(RANDOM_FILE) && !defined(WIN32) if(!seeded) { /* if there's a random file to read a seed from, use it */ diff --git a/Utilities/cmcurl/lib/rtsp.c b/Utilities/cmcurl/lib/rtsp.c index 9d27929..aef3560 100644 --- a/Utilities/cmcurl/lib/rtsp.c +++ b/Utilities/cmcurl/lib/rtsp.c @@ -145,7 +145,8 @@ static unsigned int rtsp_conncheck(struct Curl_easy *data, (void)data; if(checks_to_perform & CONNCHECK_ISDEAD) { - if(!Curl_conn_is_alive(data, conn)) + bool input_pending; + if(!Curl_conn_is_alive(data, conn, &input_pending)) ret_val |= CONNRESULT_DEAD; } @@ -755,12 +756,14 @@ CURLcode rtp_client_write(struct Curl_easy *data, char *ptr, size_t len) CURLcode Curl_rtsp_parseheader(struct Curl_easy *data, char *header) { - long CSeq = 0; - if(checkprefix("CSeq:", header)) { - /* Store the received CSeq. Match is verified in rtsp_done */ - int nc = sscanf(&header[4], ": %ld", &CSeq); - if(nc == 1) { + long CSeq = 0; + char *endp; + char *p = &header[5]; + while(ISBLANK(*p)) + p++; + CSeq = strtol(p, &endp, 10); + if(p != endp) { struct RTSP *rtsp = data->req.p.rtsp; rtsp->CSeq_recv = CSeq; /* mark the request */ data->state.rtsp_CSeq_recv = CSeq; /* update the handle */ diff --git a/Utilities/cmcurl/lib/select.c b/Utilities/cmcurl/lib/select.c index 3b8d468..61cce61 100644 --- a/Utilities/cmcurl/lib/select.c +++ b/Utilities/cmcurl/lib/select.c @@ -230,14 +230,14 @@ int Curl_socket_check(curl_socket_t readfd0, /* two sockets to read from */ if(readfd0 != CURL_SOCKET_BAD) { if(pfd[num].revents & (POLLRDNORM|POLLIN|POLLERR|POLLHUP)) r |= CURL_CSELECT_IN; - if(pfd[num].revents & (POLLRDBAND|POLLPRI|POLLNVAL)) + if(pfd[num].revents & (POLLPRI|POLLNVAL)) r |= CURL_CSELECT_ERR; num++; } if(readfd1 != CURL_SOCKET_BAD) { if(pfd[num].revents & (POLLRDNORM|POLLIN|POLLERR|POLLHUP)) r |= CURL_CSELECT_IN2; - if(pfd[num].revents & (POLLRDBAND|POLLPRI|POLLNVAL)) + if(pfd[num].revents & (POLLPRI|POLLNVAL)) r |= CURL_CSELECT_ERR; num++; } diff --git a/Utilities/cmcurl/lib/setopt.c b/Utilities/cmcurl/lib/setopt.c index 604693a..6bb8879 100644 --- a/Utilities/cmcurl/lib/setopt.c +++ b/Utilities/cmcurl/lib/setopt.c @@ -899,7 +899,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) case CURL_HTTP_VERSION_NONE: #ifdef USE_HTTP2 /* TODO: this seems an undesirable quirk to force a behaviour on - * lower implementations that they should recognize independantly? */ + * lower implementations that they should recognize independently? */ arg = CURL_HTTP_VERSION_2TLS; #endif /* accepted */ @@ -2369,7 +2369,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) arg = va_arg(param, long); if((arg < CURLUSESSL_NONE) || (arg >= CURLUSESSL_LAST)) return CURLE_BAD_FUNCTION_ARGUMENT; - data->set.use_ssl = (curl_usessl)arg; + data->set.use_ssl = (unsigned char)arg; break; case CURLOPT_SSL_OPTIONS: @@ -2849,7 +2849,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) data->set.fnmatch = va_arg(param, curl_fnmatch_callback); break; case CURLOPT_CHUNK_DATA: - data->wildcard.customptr = va_arg(param, void *); + data->set.wildcardptr = va_arg(param, void *); break; case CURLOPT_FNMATCH_DATA: data->set.fnmatch_data = va_arg(param, void *); diff --git a/Utilities/cmcurl/lib/sigpipe.h b/Utilities/cmcurl/lib/sigpipe.h index 14ab25b..48761ad 100644 --- a/Utilities/cmcurl/lib/sigpipe.h +++ b/Utilities/cmcurl/lib/sigpipe.h @@ -50,7 +50,6 @@ static void sigpipe_ignore(struct Curl_easy *data, if(!data->set.no_signal) { struct sigaction action; /* first, extract the existing situation */ - memset(&ig->old_pipe_act, 0, sizeof(struct sigaction)); sigaction(SIGPIPE, NULL, &ig->old_pipe_act); action = ig->old_pipe_act; /* ignore this signal */ diff --git a/Utilities/cmcurl/lib/smb.c b/Utilities/cmcurl/lib/smb.c index dc0abe7..0762004 100644 --- a/Utilities/cmcurl/lib/smb.c +++ b/Utilities/cmcurl/lib/smb.c @@ -25,8 +25,7 @@ #include "curl_setup.h" -#if !defined(CURL_DISABLE_SMB) && defined(USE_CURL_NTLM_CORE) && \ - (SIZEOF_CURL_OFF_T > 4) +#if !defined(CURL_DISABLE_SMB) && defined(USE_CURL_NTLM_CORE) #define BUILDING_CURL_SMB_C diff --git a/Utilities/cmcurl/lib/telnet.c b/Utilities/cmcurl/lib/telnet.c index a964bfd..e4ffd85 100644 --- a/Utilities/cmcurl/lib/telnet.c +++ b/Utilities/cmcurl/lib/telnet.c @@ -770,22 +770,32 @@ static void printsub(struct Curl_easy *data, } } +static bool str_is_nonascii(const char *str) +{ + size_t len = strlen(str); + while(len--) { + if(*str & 0x80) + return TRUE; + str++; + } + return FALSE; +} + static CURLcode check_telnet_options(struct Curl_easy *data) { struct curl_slist *head; struct curl_slist *beg; - char option_keyword[128] = ""; - char option_arg[256] = ""; struct TELNET *tn = data->req.p.telnet; - struct connectdata *conn = data->conn; CURLcode result = CURLE_OK; - int binary_option; /* Add the user name as an environment variable if it was given on the command line */ if(data->state.aptr.user) { - msnprintf(option_arg, sizeof(option_arg), "USER,%s", conn->user); - beg = curl_slist_append(tn->telnet_vars, option_arg); + char buffer[256]; + if(str_is_nonascii(data->conn->user)) + return CURLE_BAD_FUNCTION_ARGUMENT; + msnprintf(buffer, sizeof(buffer), "USER,%s", data->conn->user); + beg = curl_slist_append(tn->telnet_vars, buffer); if(!beg) { curl_slist_free_all(tn->telnet_vars); tn->telnet_vars = NULL; @@ -795,68 +805,100 @@ static CURLcode check_telnet_options(struct Curl_easy *data) tn->us_preferred[CURL_TELOPT_NEW_ENVIRON] = CURL_YES; } - for(head = data->set.telnet_options; head; head = head->next) { - if(sscanf(head->data, "%127[^= ]%*[ =]%255s", - option_keyword, option_arg) == 2) { - - /* Terminal type */ - if(strcasecompare(option_keyword, "TTYPE")) { - strncpy(tn->subopt_ttype, option_arg, 31); - tn->subopt_ttype[31] = 0; /* String termination */ - tn->us_preferred[CURL_TELOPT_TTYPE] = CURL_YES; + for(head = data->set.telnet_options; head && !result; head = head->next) { + size_t olen; + char *option = head->data; + char *arg; + char *sep = strchr(option, '='); + if(sep) { + olen = sep - option; + arg = ++sep; + if(str_is_nonascii(arg)) continue; - } + switch(olen) { + case 5: + /* Terminal type */ + if(strncasecompare(option, "TTYPE", 5)) { + strncpy(tn->subopt_ttype, arg, 31); + tn->subopt_ttype[31] = 0; /* String termination */ + tn->us_preferred[CURL_TELOPT_TTYPE] = CURL_YES; + } + else + result = CURLE_UNKNOWN_OPTION; + break; - /* Display variable */ - if(strcasecompare(option_keyword, "XDISPLOC")) { - strncpy(tn->subopt_xdisploc, option_arg, 127); - tn->subopt_xdisploc[127] = 0; /* String termination */ - tn->us_preferred[CURL_TELOPT_XDISPLOC] = CURL_YES; - continue; - } + case 8: + /* Display variable */ + if(strncasecompare(option, "XDISPLOC", 8)) { + strncpy(tn->subopt_xdisploc, arg, 127); + tn->subopt_xdisploc[127] = 0; /* String termination */ + tn->us_preferred[CURL_TELOPT_XDISPLOC] = CURL_YES; + } + else + result = CURLE_UNKNOWN_OPTION; + break; - /* Environment variable */ - if(strcasecompare(option_keyword, "NEW_ENV")) { - beg = curl_slist_append(tn->telnet_vars, option_arg); - if(!beg) { - result = CURLE_OUT_OF_MEMORY; - break; + case 7: + /* Environment variable */ + if(strncasecompare(option, "NEW_ENV", 7)) { + beg = curl_slist_append(tn->telnet_vars, arg); + if(!beg) { + result = CURLE_OUT_OF_MEMORY; + break; + } + tn->telnet_vars = beg; + tn->us_preferred[CURL_TELOPT_NEW_ENVIRON] = CURL_YES; } - tn->telnet_vars = beg; - tn->us_preferred[CURL_TELOPT_NEW_ENVIRON] = CURL_YES; - continue; - } + else + result = CURLE_UNKNOWN_OPTION; + break; - /* Window Size */ - if(strcasecompare(option_keyword, "WS")) { - if(sscanf(option_arg, "%hu%*[xX]%hu", - &tn->subopt_wsx, &tn->subopt_wsy) == 2) - tn->us_preferred[CURL_TELOPT_NAWS] = CURL_YES; - else { - failf(data, "Syntax error in telnet option: %s", head->data); - result = CURLE_SETOPT_OPTION_SYNTAX; - break; + case 2: + /* Window Size */ + if(strncasecompare(option, "WS", 2)) { + char *p; + unsigned long x = strtoul(arg, &p, 10); + unsigned long y = 0; + if(x && (x <= 0xffff) && Curl_raw_tolower(*p) == 'x') { + p++; + y = strtoul(p, NULL, 10); + if(y && (y <= 0xffff)) { + tn->subopt_wsx = (unsigned short)x; + tn->subopt_wsy = (unsigned short)y; + tn->us_preferred[CURL_TELOPT_NAWS] = CURL_YES; + } + } + if(!y) { + failf(data, "Syntax error in telnet option: %s", head->data); + result = CURLE_SETOPT_OPTION_SYNTAX; + } } - continue; - } + else + result = CURLE_UNKNOWN_OPTION; + break; - /* To take care or not of the 8th bit in data exchange */ - if(strcasecompare(option_keyword, "BINARY")) { - binary_option = atoi(option_arg); - if(binary_option != 1) { - tn->us_preferred[CURL_TELOPT_BINARY] = CURL_NO; - tn->him_preferred[CURL_TELOPT_BINARY] = CURL_NO; + case 6: + /* To take care or not of the 8th bit in data exchange */ + if(strncasecompare(option, "BINARY", 6)) { + int binary_option = atoi(arg); + if(binary_option != 1) { + tn->us_preferred[CURL_TELOPT_BINARY] = CURL_NO; + tn->him_preferred[CURL_TELOPT_BINARY] = CURL_NO; + } } - continue; + else + result = CURLE_UNKNOWN_OPTION; + break; + default: + failf(data, "Unknown telnet option %s", head->data); + result = CURLE_UNKNOWN_OPTION; + break; } - - failf(data, "Unknown telnet option %s", head->data); - result = CURLE_UNKNOWN_OPTION; - break; } - failf(data, "Syntax error in telnet option: %s", head->data); - result = CURLE_SETOPT_OPTION_SYNTAX; - break; + else { + failf(data, "Syntax error in telnet option: %s", head->data); + result = CURLE_SETOPT_OPTION_SYNTAX; + } } if(result) { @@ -881,8 +923,6 @@ static void suboption(struct Curl_easy *data) ssize_t bytes_written; size_t len; int err; - char varname[128] = ""; - char varval[128] = ""; struct TELNET *tn = data->req.p.telnet; struct connectdata *conn = data->conn; @@ -920,19 +960,18 @@ static void suboption(struct Curl_easy *data) for(v = tn->telnet_vars; v; v = v->next) { size_t tmplen = (strlen(v->data) + 1); - /* Add the variable only if it fits */ + /* Add the variable if it fits */ if(len + tmplen < (int)sizeof(temp)-6) { - int rv; - char sep[2] = ""; - varval[0] = 0; - rv = sscanf(v->data, "%127[^,]%1[,]%127s", varname, sep, varval); - if(rv == 1) + char *s = strchr(v->data, ','); + if(!s) len += msnprintf((char *)&temp[len], sizeof(temp) - len, - "%c%s", CURL_NEW_ENV_VAR, varname); - else if(rv >= 2) + "%c%s", CURL_NEW_ENV_VAR, v->data); + else { + size_t vlen = s - v->data; len += msnprintf((char *)&temp[len], sizeof(temp) - len, - "%c%s%c%s", CURL_NEW_ENV_VAR, varname, - CURL_NEW_ENV_VALUE, varval); + "%c%.*s%c%s", CURL_NEW_ENV_VAR, + (int)vlen, v->data, CURL_NEW_ENV_VALUE, ++s); + } } } msnprintf((char *)&temp[len], sizeof(temp) - len, diff --git a/Utilities/cmcurl/lib/transfer.c b/Utilities/cmcurl/lib/transfer.c index 69df214..a283952 100644 --- a/Utilities/cmcurl/lib/transfer.c +++ b/Utilities/cmcurl/lib/transfer.c @@ -980,7 +980,15 @@ static CURLcode readwrite_upload(struct Curl_easy *data, if(result) return result; - win_update_buffer_size(conn->writesockfd); +#if defined(WIN32) && defined(USE_WINSOCK) + { + struct curltime n = Curl_now(); + if(Curl_timediff(n, k->last_sndbuf_update) > 1000) { + win_update_buffer_size(conn->writesockfd); + k->last_sndbuf_update = n; + } + } +#endif if(k->pendingheader) { /* parts of what was sent was header */ @@ -1226,8 +1234,7 @@ CURLcode Curl_readwrite(struct connectdata *conn, } /* Now update the "done" boolean we return */ - *done = (0 == (k->keepon&(KEEP_RECV|KEEP_SEND| - KEEP_RECV_PAUSE|KEEP_SEND_PAUSE))) ? TRUE : FALSE; + *done = (0 == (k->keepon&(KEEP_RECVBITS|KEEP_SENDBITS))) ? TRUE : FALSE; result = CURLE_OK; out: if(result) @@ -1394,7 +1401,13 @@ CURLcode Curl_pretransfer(struct Curl_easy *data) #ifndef CURL_DISABLE_FTP data->state.wildcardmatch = data->set.wildcard_enabled; if(data->state.wildcardmatch) { - struct WildcardData *wc = &data->wildcard; + struct WildcardData *wc; + if(!data->wildcard) { + data->wildcard = calloc(1, sizeof(struct WildcardData)); + if(!data->wildcard) + return CURLE_OUT_OF_MEMORY; + } + wc = data->wildcard; if(wc->state < CURLWC_INIT) { result = Curl_wildcard_init(wc); /* init wildcard structures */ if(result) diff --git a/Utilities/cmcurl/lib/url.c b/Utilities/cmcurl/lib/url.c index 1bb93df..f7b4bbb 100644 --- a/Utilities/cmcurl/lib/url.c +++ b/Utilities/cmcurl/lib/url.c @@ -288,33 +288,6 @@ static const struct Curl_handler * const protocols[] = { (struct Curl_handler *) NULL }; -/* - * Dummy handler for undefined protocol schemes. - */ - -static const struct Curl_handler Curl_handler_dummy = { - "<no protocol>", /* scheme */ - ZERO_NULL, /* setup_connection */ - ZERO_NULL, /* do_it */ - ZERO_NULL, /* done */ - ZERO_NULL, /* do_more */ - ZERO_NULL, /* connect_it */ - ZERO_NULL, /* connecting */ - ZERO_NULL, /* doing */ - ZERO_NULL, /* proto_getsock */ - ZERO_NULL, /* doing_getsock */ - ZERO_NULL, /* domore_getsock */ - ZERO_NULL, /* perform_getsock */ - ZERO_NULL, /* disconnect */ - ZERO_NULL, /* readwrite */ - ZERO_NULL, /* connection_check */ - ZERO_NULL, /* attach connection */ - 0, /* defport */ - 0, /* protocol */ - 0, /* family */ - PROTOPT_NONE /* flags */ -}; - void Curl_freeset(struct Curl_easy *data) { /* Free all dynamic strings stored in the data->set substructure. */ @@ -341,6 +314,11 @@ void Curl_freeset(struct Curl_easy *data) data->state.url = NULL; Curl_mime_cleanpart(&data->set.mimepost); + +#ifndef CURL_DISABLE_COOKIES + curl_slist_free_all(data->set.cookielist); + data->set.cookielist = NULL; +#endif } /* free the URL pieces */ @@ -431,9 +409,6 @@ CURLcode Curl_close(struct Curl_easy **datap) Curl_dyn_free(&data->state.headerb); Curl_safefree(data->state.ulbuf); Curl_flush_cookies(data, TRUE); -#ifndef CURL_DISABLE_COOKIES - curl_slist_free_all(data->set.cookielist); /* clean up list */ -#endif Curl_altsvc_save(data, data->asi, data->set.str[STRING_ALTSVC]); Curl_altsvc_cleanup(&data->asi); Curl_hsts_save(data, data->hsts, data->set.str[STRING_HSTS]); @@ -752,8 +727,6 @@ static void conn_free(struct Curl_easy *data, struct connectdata *conn) Curl_safefree(conn->conn_to_host.rawalloc); /* host name buffer */ Curl_safefree(conn->hostname_resolve); Curl_safefree(conn->secondaryhostname); - - Curl_llist_destroy(&conn->easyq, NULL); Curl_safefree(conn->localdev); Curl_free_primary_ssl_config(&conn->ssl_config); @@ -823,7 +796,7 @@ void Curl_disconnect(struct Curl_easy *data, disconnect and shutdown */ Curl_attach_connection(data, conn); - if(conn->handler->disconnect) + if(conn->handler && conn->handler->disconnect) /* This is set if protocol-specific cleanups should be made */ conn->handler->disconnect(data, conn, dead_connection); @@ -965,7 +938,20 @@ static bool extract_if_dead(struct connectdata *conn, } else { - dead = !Curl_conn_is_alive(data, conn); + bool input_pending; + + dead = !Curl_conn_is_alive(data, conn, &input_pending); + if(input_pending) { + /* For reuse, we want a "clean" connection state. The includes + * that we expect - in general - no waiting input data. Input + * waiting might be a TLS Notify Close, for example. We reject + * that. + * For protocols where data from other other end may arrive at + * any time (HTTP/2 PING for example), the protocol handler needs + * to install its own `connection_check` callback. + */ + dead = TRUE; + } } if(dead) { @@ -1170,14 +1156,14 @@ ConnectionExists(struct Curl_easy *data, continue; } } + } - if(!Curl_conn_is_connected(check, FIRSTSOCKET)) { - foundPendingCandidate = TRUE; - /* Don't pick a connection that hasn't connected yet */ - infof(data, "Connection #%ld isn't open enough, can't reuse", - check->connection_id); - continue; - } + if(!Curl_conn_is_connected(check, FIRSTSOCKET)) { + foundPendingCandidate = TRUE; + /* Don't pick a connection that hasn't connected yet */ + infof(data, "Connection #%ld isn't open enough, can't reuse", + check->connection_id); + continue; } #ifdef USE_UNIX_SOCKETS @@ -1291,6 +1277,11 @@ ConnectionExists(struct Curl_easy *data, } } + /* GSS delegation differences do not actually affect every connection + and auth method, but this check takes precaution before efficiency */ + if(needle->gssapi_delegation != check->gssapi_delegation) + continue; + /* If multiplexing isn't enabled on the h2 connection and h1 is explicitly requested, handle it: */ if((needle->handler->protocol & PROTO_FAMILY_HTTP) && @@ -1299,11 +1290,24 @@ ConnectionExists(struct Curl_easy *data, || ((check->httpversion >= 30) && (data->state.httpwant < CURL_HTTP_VERSION_3)))) continue; - - if(get_protocol_family(needle->handler) == PROTO_FAMILY_SSH) { +#ifdef USE_SSH + else if(get_protocol_family(needle->handler) & PROTO_FAMILY_SSH) { if(!ssh_config_matches(needle, check)) continue; } +#endif +#ifndef CURL_DISABLE_FTP + else if(get_protocol_family(needle->handler) & PROTO_FAMILY_FTP) { + /* Also match ACCOUNT, ALTERNATIVE-TO-USER, USE_SSL and CCC options */ + if(Curl_timestrcmp(needle->proto.ftpc.account, + check->proto.ftpc.account) || + Curl_timestrcmp(needle->proto.ftpc.alternative_to_user, + check->proto.ftpc.alternative_to_user) || + (needle->proto.ftpc.use_ssl != check->proto.ftpc.use_ssl) || + (needle->proto.ftpc.ccc != check->proto.ftpc.ccc)) + continue; + } +#endif if((needle->handler->flags&PROTOPT_SSL) #ifndef CURL_DISABLE_PROXY @@ -1494,10 +1498,6 @@ static struct connectdata *allocate_conn(struct Curl_easy *data) if(!conn) return NULL; - conn->handler = &Curl_handler_dummy; /* Be sure we have a handler defined - already from start to avoid NULL - situations and checks */ - /* and we setup a few fields in case we end up actually using this struct */ conn->sock[FIRSTSOCKET] = CURL_SOCKET_BAD; /* no file descriptor */ @@ -1589,11 +1589,11 @@ static struct connectdata *allocate_conn(struct Curl_easy *data) conn->fclosesocket = data->set.fclosesocket; conn->closesocket_client = data->set.closesocket_client; conn->lastused = Curl_now(); /* used now */ + conn->gssapi_delegation = data->set.gssapi_delegation; return conn; error: - Curl_llist_destroy(&conn->easyq, NULL); free(conn->localdev); free(conn); return NULL; diff --git a/Utilities/cmcurl/lib/urlapi.c b/Utilities/cmcurl/lib/urlapi.c index 29927b3..62e3233 100644 --- a/Utilities/cmcurl/lib/urlapi.c +++ b/Utilities/cmcurl/lib/urlapi.c @@ -57,6 +57,15 @@ /* scheme is not URL encoded, the longest libcurl supported ones are... */ #define MAX_SCHEME_LEN 40 +/* + * If ENABLE_IPV6 is disabled, we still want to parse IPv6 addresses, so make + * sure we have _some_ value for AF_INET6 without polluting our fake value + * everywhere. + */ +#if !defined(ENABLE_IPV6) && !defined(AF_INET6) +#define AF_INET6 (AF_INET + 1) +#endif + /* Internal representation of CURLU. Point to URL-encoded strings. */ struct Curl_URL { char *scheme; @@ -599,7 +608,8 @@ static CURLUcode hostname_check(struct Curl_URL *u, char *hostname, return CURLUE_BAD_IPV6; /* hostname is fine */ } -#ifdef ENABLE_IPV6 + + /* Check the IPv6 address. */ { char dest[16]; /* fits a binary IPv6 address */ char norm[MAX_IPADR_LEN]; @@ -616,11 +626,10 @@ static CURLUcode hostname_check(struct Curl_URL *u, char *hostname, } hostname[hlen] = ']'; /* restore ending bracket */ } -#endif } else { /* letters from the second string are not ok */ - len = strcspn(hostname, " \r\n\t/:#?!@{}[]\\$\'\"^`*<>=;,+&()"); + len = strcspn(hostname, " \r\n\t/:#?!@{}[]\\$\'\"^`*<>=;,+&()%"); if(hlen != len) /* hostname with bad content */ return CURLUE_BAD_HOSTNAME; @@ -1341,7 +1350,7 @@ void curl_url_cleanup(CURLU *u) } \ } while(0) -CURLU *curl_url_dup(CURLU *in) +CURLU *curl_url_dup(const CURLU *in) { struct Curl_URL *u = calloc(sizeof(struct Curl_URL), 1); if(u) { @@ -1362,10 +1371,10 @@ CURLU *curl_url_dup(CURLU *in) return NULL; } -CURLUcode curl_url_get(CURLU *u, CURLUPart what, +CURLUcode curl_url_get(const CURLU *u, CURLUPart what, char **part, unsigned int flags) { - char *ptr; + const char *ptr; CURLUcode ifmissing = CURLUE_UNKNOWN_PART; char portbuf[7]; bool urldecode = (flags & CURLU_URLDECODE)?1:0; @@ -1432,11 +1441,8 @@ CURLUcode curl_url_get(CURLU *u, CURLUPart what, break; case CURLUPART_PATH: ptr = u->path; - if(!ptr) { - ptr = u->path = strdup("/"); - if(!u->path) - return CURLUE_OUT_OF_MEMORY; - } + if(!ptr) + ptr = "/"; break; case CURLUPART_QUERY: ptr = u->query; @@ -1546,8 +1552,7 @@ CURLUcode curl_url_get(CURLU *u, CURLUPart what, return CURLUE_OUT_OF_MEMORY; host++; } - free(u->host); - u->host = Curl_dyn_ptr(&enc); + allochost = Curl_dyn_ptr(&enc); } } diff --git a/Utilities/cmcurl/lib/urldata.h b/Utilities/cmcurl/lib/urldata.h index 4cfffa7..8b54518 100644 --- a/Utilities/cmcurl/lib/urldata.h +++ b/Utilities/cmcurl/lib/urldata.h @@ -168,7 +168,7 @@ typedef CURLcode (*Curl_datastream)(struct Curl_easy *data, #include "rtsp.h" #include "smb.h" #include "mqtt.h" -#include "wildcard.h" +#include "ftplistparser.h" #include "multihandle.h" #include "c-hyper.h" #include "cf-socket.h" @@ -687,6 +687,10 @@ struct SingleRequest { #ifndef CURL_DISABLE_DOH struct dohdata *doh; /* DoH specific data for this request */ #endif +#if defined(WIN32) && defined(USE_WINSOCK) + struct curltime last_sndbuf_update; /* last time readwrite_upload called + win_update_buffer_size */ +#endif unsigned char setcookies; unsigned char writer_stack_depth; /* Unencoding stack depth. */ BIT(header); /* incoming data has HTTP header */ @@ -1057,6 +1061,7 @@ struct connectdata { unsigned char ip_version; /* copied from the Curl_easy at creation time */ unsigned char httpversion; /* the HTTP version*10 reported by the server */ unsigned char connect_only; + unsigned char gssapi_delegation; /* inherited from set.gssapi_delegation */ }; /* The end of connectdata. */ @@ -1374,7 +1379,7 @@ struct UrlState { struct dynbuf trailers_buf; /* a buffer containing the compiled trailing headers */ struct Curl_llist httphdrs; /* received headers */ - struct curl_header headerout; /* for external purposes */ + struct curl_header headerout[2]; /* for external purposes */ struct Curl_header_store *prevhead; /* the latest added header */ trailers_state trailers_state; /* whether we are sending trailers and what stage are we at */ @@ -1713,8 +1718,6 @@ struct UserDefined { #ifndef CURL_DISABLE_NETRC unsigned char use_netrc; /* enum CURL_NETRC_OPTION values */ #endif - curl_usessl use_ssl; /* if AUTH TLS is to be attempted etc, for FTP or - IMAP or POP3 or others! */ unsigned int new_file_perms; /* when creating remote files */ char *str[STRING_LAST]; /* array of strings, pointing to allocated memory */ struct curl_blob *blobs[BLOB_LAST]; @@ -1739,6 +1742,7 @@ struct UserDefined { curl_fnmatch_callback fnmatch; /* callback to decide which file corresponds to pattern (e.g. if WILDCARDMATCH is on) */ void *fnmatch_data; + void *wildcardptr; #endif /* GSS-API credential delegation, see the documentation of CURLOPT_GSSAPI_DELEGATION */ @@ -1773,6 +1777,8 @@ struct UserDefined { BIT(mail_rcpt_allowfails); /* allow RCPT TO command to fail for some recipients */ #endif + unsigned char use_ssl; /* if AUTH TLS is to be attempted etc, for FTP or + IMAP or POP3 or others! (type: curl_usessl)*/ unsigned char connect_only; /* make connection/request, then let application use the socket */ BIT(is_fread_set); /* has read callback been set to non-NULL? */ @@ -1934,7 +1940,7 @@ struct Curl_easy { struct UrlState state; /* struct for fields used for state info and other dynamic purposes */ #ifndef CURL_DISABLE_FTP - struct WildcardData wildcard; /* wildcard download state info */ + struct WildcardData *wildcard; /* wildcard download state info */ #endif struct PureInfo info; /* stats, reports and info data */ struct curl_tlssessioninfo tsi; /* Information about the TLS session, only diff --git a/Utilities/cmcurl/lib/version.c b/Utilities/cmcurl/lib/version.c index 55b54a0..5800ad3 100644 --- a/Utilities/cmcurl/lib/version.c +++ b/Utilities/cmcurl/lib/version.c @@ -62,7 +62,15 @@ #endif #ifdef HAVE_BROTLI +#if defined(__GNUC__) +/* Ignore -Wvla warnings in brotli headers */ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wvla" +#endif #include <brotli/decode.h> +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif #endif #ifdef HAVE_ZSTD @@ -357,8 +365,7 @@ static const char * const protocols[] = { #ifdef USE_SSH "sftp", #endif -#if !defined(CURL_DISABLE_SMB) && defined(USE_CURL_NTLM_CORE) && \ - (SIZEOF_CURL_OFF_T > 4) +#if !defined(CURL_DISABLE_SMB) && defined(USE_CURL_NTLM_CORE) "smb", # ifdef USE_SSL "smbs", diff --git a/Utilities/cmcurl/lib/vquic/curl_msh3.c b/Utilities/cmcurl/lib/vquic/curl_msh3.c index 1930703..5308999 100644 --- a/Utilities/cmcurl/lib/vquic/curl_msh3.c +++ b/Utilities/cmcurl/lib/vquic/curl_msh3.c @@ -548,7 +548,6 @@ static CURLcode cf_msh3_data_event(struct Curl_cfilter *cf, struct Curl_easy *data, int event, int arg1, void *arg2) { - struct cf_msh3_ctx *ctx = cf->ctx; struct HTTP *stream = data->req.p.http; CURLcode result = CURLE_OK; @@ -579,11 +578,6 @@ static CURLcode cf_msh3_data_event(struct Curl_cfilter *cf, DEBUGF(LOG_CF(data, cf, "req: update info")); cf_msh3_active(cf, data); break; - case CF_CTRL_CONN_REPORT_STATS: - if(cf->sockindex == FIRSTSOCKET) - Curl_pgrsTimeWas(data, TIMER_APPCONNECT, ctx->handshake_at); - break; - default: break; } @@ -753,6 +747,19 @@ static CURLcode cf_msh3_query(struct Curl_cfilter *cf, *pres1 = 100; return CURLE_OK; } + case CF_QUERY_TIMER_CONNECT: { + struct curltime *when = pres2; + /* we do not know when the first byte arrived */ + if(cf->connected) + *when = ctx->handshake_at; + return CURLE_OK; + } + case CF_QUERY_TIMER_APPCONNECT: { + struct curltime *when = pres2; + if(cf->connected) + *when = ctx->handshake_at; + return CURLE_OK; + } default: break; } @@ -762,11 +769,13 @@ static CURLcode cf_msh3_query(struct Curl_cfilter *cf, } static bool cf_msh3_conn_is_alive(struct Curl_cfilter *cf, - struct Curl_easy *data) + struct Curl_easy *data, + bool *input_pending) { struct cf_msh3_ctx *ctx = cf->ctx; (void)data; + *input_pending = FALSE; return ctx && ctx->sock[SP_LOCAL] != CURL_SOCKET_BAD && ctx->qconn && ctx->connected; } diff --git a/Utilities/cmcurl/lib/vquic/curl_ngtcp2.c b/Utilities/cmcurl/lib/vquic/curl_ngtcp2.c index ffdaead..d2d0a3a 100644 --- a/Utilities/cmcurl/lib/vquic/curl_ngtcp2.c +++ b/Utilities/cmcurl/lib/vquic/curl_ngtcp2.c @@ -64,6 +64,8 @@ #include "vtls/vtls.h" #include "curl_ngtcp2.h" +#include "warnless.h" + /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" @@ -901,7 +903,7 @@ static int cf_ngtcp2_get_select_socks(struct Curl_cfilter *cf, rv |= GETSOCK_READSOCK(0); /* we're still uploading or the HTTP/2 layer wants to send data */ - if((k->keepon & (KEEP_SEND|KEEP_SEND_PAUSE)) == KEEP_SEND && + if((k->keepon & KEEP_SENDBITS) == KEEP_SEND && (!stream->h3out || stream->h3out->used < H3_SEND_SIZE) && ngtcp2_conn_get_cwnd_left(ctx->qconn) && ngtcp2_conn_get_max_data_left(ctx->qconn) && @@ -951,7 +953,7 @@ static int cb_h3_stream_close(nghttp3_conn *conn, int64_t stream_id, } /* - * write_resp_raw() copies resonse data in raw format to the `data`'s + * write_resp_raw() copies response data in raw format to the `data`'s * receive buffer. If not enough space is available, it appends to the * `data`'s overflow buffer. */ @@ -1762,7 +1764,7 @@ static CURLcode cf_process_ingress(struct Curl_cfilter *cf, ssize_t recvd; int rv; uint8_t buf[65536]; - size_t bufsize = sizeof(buf); + int bufsize = (int)sizeof(buf); size_t pktcount = 0, total_recvd = 0; struct sockaddr_storage remote_addr; socklen_t remote_addrlen; @@ -2107,13 +2109,6 @@ static CURLcode cf_ngtcp2_data_event(struct Curl_cfilter *cf, } } break; - case CF_CTRL_CONN_REPORT_STATS: - if(cf->sockindex == FIRSTSOCKET) { - if(ctx->got_first_byte) - Curl_pgrsTimeWas(data, TIMER_CONNECT, ctx->first_byte_at); - Curl_pgrsTimeWas(data, TIMER_APPCONNECT, ctx->handshake_at); - } - break; default: break; } @@ -2127,7 +2122,6 @@ static void cf_ngtcp2_ctx_clear(struct cf_ngtcp2_ctx *ctx) if(ctx->qlogfd != -1) { close(ctx->qlogfd); - ctx->qlogfd = -1; } #ifdef USE_OPENSSL if(ctx->ssl) @@ -2155,6 +2149,7 @@ static void cf_ngtcp2_ctx_clear(struct cf_ngtcp2_ctx *ctx) ngtcp2_conn_del(ctx->qconn); memset(ctx, 0, sizeof(*ctx)); + ctx->qlogfd = -1; ctx->call_data = save; } @@ -2176,7 +2171,7 @@ static void cf_ngtcp2_close(struct Curl_cfilter *cf, struct Curl_easy *data) (uint8_t *)buffer, sizeof(buffer), &ctx->last_error, ts); if(rc > 0) { - while((send(ctx->q.sockfd, buffer, rc, 0) == -1) && + while((send(ctx->q.sockfd, buffer, (SEND_TYPE_ARG3)rc, 0) == -1) && SOCKERRNO == EINTR); } @@ -2200,6 +2195,7 @@ static void cf_ngtcp2_destroy(struct Curl_cfilter *cf, struct Curl_easy *data) } cf->ctx = NULL; /* No CF_DATA_RESTORE(cf, save) possible */ + (void)save; } /* @@ -2428,6 +2424,18 @@ static CURLcode cf_ngtcp2_query(struct Curl_cfilter *cf, else *pres1 = -1; return CURLE_OK; + case CF_QUERY_TIMER_CONNECT: { + struct curltime *when = pres2; + if(ctx->got_first_byte) + *when = ctx->first_byte_at; + return CURLE_OK; + } + case CF_QUERY_TIMER_APPCONNECT: { + struct curltime *when = pres2; + if(cf->connected) + *when = ctx->handshake_at; + return CURLE_OK; + } default: break; } @@ -2436,6 +2444,32 @@ static CURLcode cf_ngtcp2_query(struct Curl_cfilter *cf, CURLE_UNKNOWN_OPTION; } +static bool cf_ngtcp2_conn_is_alive(struct Curl_cfilter *cf, + struct Curl_easy *data, + bool *input_pending) +{ + bool alive = TRUE; + + *input_pending = FALSE; + if(!cf->next || !cf->next->cft->is_alive(cf->next, data, input_pending)) + return FALSE; + + if(*input_pending) { + /* This happens before we've sent off a request and the connection is + not in use by any other transfer, there shouldn't be any data here, + only "protocol frames" */ + *input_pending = FALSE; + Curl_attach_connection(data, cf->conn); + if(cf_process_ingress(cf, data)) + alive = FALSE; + else { + alive = TRUE; + } + Curl_detach_connection(data); + } + + return alive; +} struct Curl_cftype Curl_cft_http3 = { "HTTP/3", @@ -2450,7 +2484,7 @@ struct Curl_cftype Curl_cft_http3 = { cf_ngtcp2_send, cf_ngtcp2_recv, cf_ngtcp2_data_event, - Curl_cf_def_conn_is_alive, + cf_ngtcp2_conn_is_alive, Curl_cf_def_conn_keep_alive, cf_ngtcp2_query, }; @@ -2470,6 +2504,7 @@ CURLcode Curl_cf_ngtcp2_create(struct Curl_cfilter **pcf, result = CURLE_OUT_OF_MEMORY; goto out; } + ctx->qlogfd = -1; cf_ngtcp2_ctx_clear(ctx); result = Curl_cf_create(&cf, &Curl_cft_http3, ctx); diff --git a/Utilities/cmcurl/lib/vquic/curl_quiche.c b/Utilities/cmcurl/lib/vquic/curl_quiche.c index 54408d7..87a221c 100644 --- a/Utilities/cmcurl/lib/vquic/curl_quiche.c +++ b/Utilities/cmcurl/lib/vquic/curl_quiche.c @@ -444,7 +444,7 @@ static CURLcode cf_process_ingress(struct Curl_cfilter *cf, struct cf_quiche_ctx *ctx = cf->ctx; int64_t stream3_id = data->req.p.http? data->req.p.http->stream3_id : -1; uint8_t buf[65536]; - size_t bufsize = sizeof(buf); + int bufsize = (int)sizeof(buf); struct sockaddr_storage remote_addr; socklen_t remote_addrlen; quiche_recv_info recv_info; @@ -950,7 +950,7 @@ static int cf_quiche_get_select_socks(struct Curl_cfilter *cf, rv |= GETSOCK_READSOCK(0); /* we're still uploading or the HTTP/3 layer wants to send data */ - if(((k->keepon & (KEEP_SEND|KEEP_SEND_PAUSE)) == KEEP_SEND) + if(((k->keepon & KEEP_SENDBITS) == KEEP_SEND) && stream_is_writeable(cf, data)) rv |= GETSOCK_WRITESOCK(0); @@ -1016,13 +1016,6 @@ static CURLcode cf_quiche_data_event(struct Curl_cfilter *cf, case CF_CTRL_DATA_IDLE: /* anything to do? */ break; - case CF_CTRL_CONN_REPORT_STATS: - if(cf->sockindex == FIRSTSOCKET) { - if(ctx->got_first_byte) - Curl_pgrsTimeWas(data, TIMER_CONNECT, ctx->first_byte_at); - Curl_pgrsTimeWas(data, TIMER_APPCONNECT, ctx->handshake_at); - } - break; default: break; } @@ -1346,6 +1339,18 @@ static CURLcode cf_quiche_query(struct Curl_cfilter *cf, else *pres1 = -1; return CURLE_OK; + case CF_QUERY_TIMER_CONNECT: { + struct curltime *when = pres2; + if(ctx->got_first_byte) + *when = ctx->first_byte_at; + return CURLE_OK; + } + case CF_QUERY_TIMER_APPCONNECT: { + struct curltime *when = pres2; + if(cf->connected) + *when = ctx->handshake_at; + return CURLE_OK; + } default: break; } @@ -1354,6 +1359,32 @@ static CURLcode cf_quiche_query(struct Curl_cfilter *cf, CURLE_UNKNOWN_OPTION; } +static bool cf_quiche_conn_is_alive(struct Curl_cfilter *cf, + struct Curl_easy *data, + bool *input_pending) +{ + bool alive = TRUE; + + *input_pending = FALSE; + if(!cf->next || !cf->next->cft->is_alive(cf->next, data, input_pending)) + return FALSE; + + if(*input_pending) { + /* This happens before we've sent off a request and the connection is + not in use by any other transfer, there shouldn't be any data here, + only "protocol frames" */ + *input_pending = FALSE; + Curl_attach_connection(data, cf->conn); + if(cf_process_ingress(cf, data)) + alive = FALSE; + else { + alive = TRUE; + } + Curl_detach_connection(data); + } + + return alive; +} struct Curl_cftype Curl_cft_http3 = { "HTTP/3", @@ -1368,7 +1399,7 @@ struct Curl_cftype Curl_cft_http3 = { cf_quiche_send, cf_quiche_recv, cf_quiche_data_event, - Curl_cf_def_conn_is_alive, + cf_quiche_conn_is_alive, Curl_cf_def_conn_keep_alive, cf_quiche_query, }; diff --git a/Utilities/cmcurl/lib/vquic/vquic.c b/Utilities/cmcurl/lib/vquic/vquic.c index 5f4f30d..bbdeabd 100644 --- a/Utilities/cmcurl/lib/vquic/vquic.c +++ b/Utilities/cmcurl/lib/vquic/vquic.c @@ -167,7 +167,8 @@ static CURLcode do_sendmsg(struct Curl_cfilter *cf, *psent = 0; - while((sent = send(qctx->sockfd, (const char *)pkt, pktlen, 0)) == -1 && + while((sent = send(qctx->sockfd, + (const char *)pkt, (SEND_TYPE_ARG3)pktlen, 0)) == -1 && SOCKERRNO == EINTR) ; @@ -363,6 +364,10 @@ bool Curl_conn_is_http3(const struct Curl_easy *data, CURLcode Curl_conn_may_http3(struct Curl_easy *data, const struct connectdata *conn) { + if(conn->transport == TRNSPRT_UNIX) { + /* cannot do QUIC over a unix domain socket */ + return CURLE_QUIC_CONNECT_ERROR; + } if(!(conn->handler->flags & PROTOPT_SSL)) { failf(data, "HTTP/3 requested for non-HTTPS URL"); return CURLE_URL_MALFORMAT; diff --git a/Utilities/cmcurl/lib/vssh/libssh.c b/Utilities/cmcurl/lib/vssh/libssh.c index 1115318..b31f741 100644 --- a/Utilities/cmcurl/lib/vssh/libssh.c +++ b/Utilities/cmcurl/lib/vssh/libssh.c @@ -685,7 +685,6 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block) struct ssh_conn *sshc = &conn->proto.sshc; curl_socket_t sock = conn->sock[FIRSTSOCKET]; int rc = SSH_NO_ERROR, err; - char *new_readdir_line; int seekerr = CURL_SEEKFUNC_OK; const char *err_msg; *block = 0; /* we're not blocking by default */ @@ -1432,7 +1431,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block) break; case SSH_SFTP_READDIR: - + Curl_dyn_reset(&sshc->readdir_buf); if(sshc->readdir_attrs) sftp_attributes_free(sshc->readdir_attrs); @@ -1468,17 +1467,12 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block) sshc->readdir_len); } else { - sshc->readdir_currLen = strlen(sshc->readdir_longentry); - sshc->readdir_totalLen = 80 + sshc->readdir_currLen; - sshc->readdir_line = calloc(sshc->readdir_totalLen, 1); - if(!sshc->readdir_line) { - state(data, SSH_SFTP_CLOSE); + if(Curl_dyn_add(&sshc->readdir_buf, sshc->readdir_longentry)) { sshc->actualcode = CURLE_OUT_OF_MEMORY; + state(data, SSH_STOP); break; } - memcpy(sshc->readdir_line, sshc->readdir_longentry, - sshc->readdir_currLen); if((sshc->readdir_attrs->flags & SSH_FILEXFER_ATTR_PERMISSIONS) && ((sshc->readdir_attrs->permissions & SSH_S_IFMT) == SSH_S_IFLNK)) { @@ -1541,24 +1535,11 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block) Curl_safefree(sshc->readdir_linkPath); - /* get room for the filename and extra output */ - sshc->readdir_totalLen += 4 + sshc->readdir_len; - new_readdir_line = Curl_saferealloc(sshc->readdir_line, - sshc->readdir_totalLen); - if(!new_readdir_line) { - sshc->readdir_line = NULL; - state(data, SSH_SFTP_CLOSE); + if(Curl_dyn_addf(&sshc->readdir_buf, " -> %s", + sshc->readdir_filename)) { sshc->actualcode = CURLE_OUT_OF_MEMORY; break; } - sshc->readdir_line = new_readdir_line; - - sshc->readdir_currLen += msnprintf(sshc->readdir_line + - sshc->readdir_currLen, - sshc->readdir_totalLen - - sshc->readdir_currLen, - " -> %s", - sshc->readdir_filename); sftp_attributes_free(sshc->readdir_link_attrs); sshc->readdir_link_attrs = NULL; @@ -1568,21 +1549,19 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block) state(data, SSH_SFTP_READDIR_BOTTOM); /* FALLTHROUGH */ case SSH_SFTP_READDIR_BOTTOM: - sshc->readdir_currLen += msnprintf(sshc->readdir_line + - sshc->readdir_currLen, - sshc->readdir_totalLen - - sshc->readdir_currLen, "\n"); - result = Curl_client_write(data, CLIENTWRITE_BODY, - sshc->readdir_line, - sshc->readdir_currLen); + if(Curl_dyn_addn(&sshc->readdir_buf, "\n", 1)) + result = CURLE_OUT_OF_MEMORY; + else + result = Curl_client_write(data, CLIENTWRITE_BODY, + Curl_dyn_ptr(&sshc->readdir_buf), + Curl_dyn_len(&sshc->readdir_buf)); if(!result) { /* output debug output if that is requested */ - Curl_debug(data, CURLINFO_DATA_OUT, sshc->readdir_line, - sshc->readdir_currLen); - data->req.bytecount += sshc->readdir_currLen; + Curl_debug(data, CURLINFO_DATA_OUT, Curl_dyn_ptr(&sshc->readdir_buf), + Curl_dyn_len(&sshc->readdir_buf)); + data->req.bytecount += Curl_dyn_len(&sshc->readdir_buf); } - Curl_safefree(sshc->readdir_line); ssh_string_free_char(sshc->readdir_tmp); sshc->readdir_tmp = NULL; @@ -2021,7 +2000,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block) Curl_safefree(sshc->rsa); Curl_safefree(sshc->quote_path1); Curl_safefree(sshc->quote_path2); - Curl_safefree(sshc->readdir_line); + Curl_dyn_free(&sshc->readdir_buf); Curl_safefree(sshc->readdir_linkPath); SSH_STRING_FREE_CHAR(sshc->homedir); @@ -2166,11 +2145,12 @@ static CURLcode myssh_setup_connection(struct Curl_easy *data, struct connectdata *conn) { struct SSHPROTO *ssh; - (void)conn; + struct ssh_conn *sshc = &conn->proto.sshc; data->req.p.ssh = ssh = calloc(1, sizeof(struct SSHPROTO)); if(!ssh) return CURLE_OUT_OF_MEMORY; + Curl_dyn_init(&sshc->readdir_buf, PATH_MAX * 2); return CURLE_OK; } diff --git a/Utilities/cmcurl/lib/vssh/libssh2.c b/Utilities/cmcurl/lib/vssh/libssh2.c index 4703eb5..f1154dc 100644 --- a/Utilities/cmcurl/lib/vssh/libssh2.c +++ b/Utilities/cmcurl/lib/vssh/libssh2.c @@ -100,10 +100,11 @@ /* Local functions: */ static const char *sftp_libssh2_strerror(unsigned long err); +#ifdef CURL_LIBSSH2_DEBUG static LIBSSH2_ALLOC_FUNC(my_libssh2_malloc); static LIBSSH2_REALLOC_FUNC(my_libssh2_realloc); static LIBSSH2_FREE_FUNC(my_libssh2_free); - +#endif static CURLcode ssh_force_knownhost_key_type(struct Curl_easy *data); static CURLcode ssh_connect(struct Curl_easy *data, bool *done); static CURLcode ssh_multi_statemach(struct Curl_easy *data, bool *done); @@ -283,6 +284,8 @@ static CURLcode libssh2_session_error_to_CURLE(int err) return CURLE_SSH; } +#ifdef CURL_LIBSSH2_DEBUG + static LIBSSH2_ALLOC_FUNC(my_libssh2_malloc) { (void)abstract; /* arg not used */ @@ -302,6 +305,8 @@ static LIBSSH2_FREE_FUNC(my_libssh2_free) free(ptr); } +#endif + /* * SSH State machine related code */ @@ -2400,7 +2405,6 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block) result = Curl_dyn_addf(&sshp->readdir, " -> %s", sshp->readdir_filename); if(result) { - sshc->readdir_line = NULL; Curl_safefree(sshp->readdir_filename); Curl_safefree(sshp->readdir_longentry); state(data, SSH_SFTP_CLOSE); @@ -3004,12 +3008,9 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block) Curl_safefree(sshc->rsa_pub); Curl_safefree(sshc->rsa); - Curl_safefree(sshc->quote_path1); Curl_safefree(sshc->quote_path2); - Curl_safefree(sshc->homedir); - Curl_safefree(sshc->readdir_line); /* the code we are about to return */ result = sshc->actualcode; @@ -3268,9 +3269,13 @@ static CURLcode ssh_connect(struct Curl_easy *data, bool *done) sock = conn->sock[FIRSTSOCKET]; #endif /* CURL_LIBSSH2_DEBUG */ +#ifdef CURL_LIBSSH2_DEBUG sshc->ssh_session = libssh2_session_init_ex(my_libssh2_malloc, my_libssh2_free, my_libssh2_realloc, data); +#else + sshc->ssh_session = libssh2_session_init(); +#endif if(!sshc->ssh_session) { failf(data, "Failure initialising ssh session"); return CURLE_FAILED_INIT; diff --git a/Utilities/cmcurl/lib/vssh/ssh.h b/Utilities/cmcurl/lib/vssh/ssh.h index 7c25555..1e1b137 100644 --- a/Utilities/cmcurl/lib/vssh/ssh.h +++ b/Utilities/cmcurl/lib/vssh/ssh.h @@ -147,7 +147,6 @@ struct ssh_conn { char *homedir; /* when doing SFTP we figure out home dir in the connect phase */ - char *readdir_line; /* end of READDIR stuff */ int secondCreateDirs; /* counter use by the code to see if the @@ -158,7 +157,8 @@ struct ssh_conn { #if defined(USE_LIBSSH) char *readdir_linkPath; - size_t readdir_len, readdir_totalLen, readdir_currLen; + size_t readdir_len; + struct dynbuf readdir_buf; /* our variables */ unsigned kbd_state; /* 0 or 1 */ ssh_key privkey; diff --git a/Utilities/cmcurl/lib/vtls/nss.c b/Utilities/cmcurl/lib/vtls/nss.c index 774cbdd..12c0390 100644 --- a/Utilities/cmcurl/lib/vtls/nss.c +++ b/Utilities/cmcurl/lib/vtls/nss.c @@ -1536,36 +1536,6 @@ static void nss_cleanup(void) initialized = 0; } -/* - * This function uses SSL_peek to determine connection status. - * - * Return codes: - * 1 means the connection is still in place - * 0 means the connection has been closed - * -1 means the connection status is unknown - */ -static int nss_check_cxn(struct Curl_cfilter *cf, struct Curl_easy *data) -{ - struct ssl_connect_data *connssl = cf->ctx; - struct ssl_backend_data *backend = connssl->backend; - int rc; - char buf; - - (void)data; - DEBUGASSERT(backend); - - rc = - PR_Recv(backend->handle, (void *)&buf, 1, PR_MSG_PEEK, - PR_SecondsToInterval(1)); - if(rc > 0) - return 1; /* connection still in place */ - - if(rc == 0) - return 0; /* connection has been closed */ - - return -1; /* connection status unknown */ -} - static void close_one(struct ssl_connect_data *connssl) { /* before the cleanup, check whether we are using a client certificate */ @@ -2524,7 +2494,7 @@ const struct Curl_ssl Curl_ssl_nss = { nss_init, /* init */ nss_cleanup, /* cleanup */ nss_version, /* version */ - nss_check_cxn, /* check_cxn */ + Curl_none_check_cxn, /* check_cxn */ /* NSS has no shutdown function provided and thus always fail */ Curl_none_shutdown, /* shutdown */ nss_data_pending, /* data_pending */ diff --git a/Utilities/cmcurl/lib/vtls/openssl.c b/Utilities/cmcurl/lib/vtls/openssl.c index e3a50bd..2ba53d9 100644 --- a/Utilities/cmcurl/lib/vtls/openssl.c +++ b/Utilities/cmcurl/lib/vtls/openssl.c @@ -1788,63 +1788,6 @@ static void ossl_cleanup(void) Curl_tls_keylog_close(); } -/* - * This function is used to determine connection status. - * - * Return codes: - * 1 means the connection is still in place - * 0 means the connection has been closed - * -1 means the connection status is unknown - */ -static int ossl_check_cxn(struct Curl_cfilter *cf, struct Curl_easy *data) -{ - /* SSL_peek takes data out of the raw recv buffer without peeking so we use - recv MSG_PEEK instead. Bug #795 */ -#ifdef MSG_PEEK - char buf; - ssize_t nread; - curl_socket_t sock = Curl_conn_cf_get_socket(cf, data); - if(sock == CURL_SOCKET_BAD) - return 0; /* no socket, consider closed */ - nread = recv((RECV_TYPE_ARG1)sock, - (RECV_TYPE_ARG2)&buf, (RECV_TYPE_ARG3)1, - (RECV_TYPE_ARG4)MSG_PEEK); - if(nread == 0) - return 0; /* connection has been closed */ - if(nread == 1) - return 1; /* connection still in place */ - else if(nread == -1) { - int err = SOCKERRNO; - if(err == EINPROGRESS || -#if defined(EAGAIN) && (EAGAIN != EWOULDBLOCK) - err == EAGAIN || -#endif - err == EWOULDBLOCK) - return 1; /* connection still in place */ - if(err == ECONNRESET || -#ifdef ECONNABORTED - err == ECONNABORTED || -#endif -#ifdef ENETDOWN - err == ENETDOWN || -#endif -#ifdef ENETRESET - err == ENETRESET || -#endif -#ifdef ESHUTDOWN - err == ESHUTDOWN || -#endif -#ifdef ETIMEDOUT - err == ETIMEDOUT || -#endif - err == ENOTCONN) - return 0; /* connection has been closed */ - } -#endif - (void)data; - return -1; /* connection status unknown */ -} - /* Selects an OpenSSL crypto engine */ static CURLcode ossl_set_engine(struct Curl_easy *data, const char *engine) @@ -4836,7 +4779,7 @@ const struct Curl_ssl Curl_ssl_openssl = { ossl_init, /* init */ ossl_cleanup, /* cleanup */ ossl_version, /* version */ - ossl_check_cxn, /* check_cxn */ + Curl_none_check_cxn, /* check_cxn */ ossl_shutdown, /* shutdown */ ossl_data_pending, /* data_pending */ ossl_random, /* random */ diff --git a/Utilities/cmcurl/lib/vtls/schannel.c b/Utilities/cmcurl/lib/vtls/schannel.c index 452fa40..6f94c7e 100644 --- a/Utilities/cmcurl/lib/vtls/schannel.c +++ b/Utilities/cmcurl/lib/vtls/schannel.c @@ -264,128 +264,133 @@ set_ssl_version_min_max(DWORD *enabled_protocols, /* longest is 26, buffer is slightly bigger */ #define LONGEST_ALG_ID 32 -#define CIPHEROPTION(X) \ - if(strcmp(#X, tmp) == 0) \ - return X +#define CIPHEROPTION(x) {#x, x} -static int -get_alg_id_by_name(char *name) -{ - char tmp[LONGEST_ALG_ID] = { 0 }; - char *nameEnd = strchr(name, ':'); - size_t n = nameEnd ? (size_t)(nameEnd - name) : strlen(name); +struct algo { + const char *name; + int id; +}; - /* reject too-long alg names */ - if(n > (LONGEST_ALG_ID - 1)) - return 0; - - strncpy(tmp, name, n); - tmp[n] = 0; - CIPHEROPTION(CALG_MD2); - CIPHEROPTION(CALG_MD4); - CIPHEROPTION(CALG_MD5); - CIPHEROPTION(CALG_SHA); - CIPHEROPTION(CALG_SHA1); - CIPHEROPTION(CALG_MAC); - CIPHEROPTION(CALG_RSA_SIGN); - CIPHEROPTION(CALG_DSS_SIGN); +static const struct algo algs[]= { + CIPHEROPTION(CALG_MD2), + CIPHEROPTION(CALG_MD4), + CIPHEROPTION(CALG_MD5), + CIPHEROPTION(CALG_SHA), + CIPHEROPTION(CALG_SHA1), + CIPHEROPTION(CALG_MAC), + CIPHEROPTION(CALG_RSA_SIGN), + CIPHEROPTION(CALG_DSS_SIGN), /* ifdefs for the options that are defined conditionally in wincrypt.h */ #ifdef CALG_NO_SIGN - CIPHEROPTION(CALG_NO_SIGN); + CIPHEROPTION(CALG_NO_SIGN), #endif - CIPHEROPTION(CALG_RSA_KEYX); - CIPHEROPTION(CALG_DES); + CIPHEROPTION(CALG_RSA_KEYX), + CIPHEROPTION(CALG_DES), #ifdef CALG_3DES_112 - CIPHEROPTION(CALG_3DES_112); + CIPHEROPTION(CALG_3DES_112), #endif - CIPHEROPTION(CALG_3DES); - CIPHEROPTION(CALG_DESX); - CIPHEROPTION(CALG_RC2); - CIPHEROPTION(CALG_RC4); - CIPHEROPTION(CALG_SEAL); + CIPHEROPTION(CALG_3DES), + CIPHEROPTION(CALG_DESX), + CIPHEROPTION(CALG_RC2), + CIPHEROPTION(CALG_RC4), + CIPHEROPTION(CALG_SEAL), #ifdef CALG_DH_SF - CIPHEROPTION(CALG_DH_SF); + CIPHEROPTION(CALG_DH_SF), #endif - CIPHEROPTION(CALG_DH_EPHEM); + CIPHEROPTION(CALG_DH_EPHEM), #ifdef CALG_AGREEDKEY_ANY - CIPHEROPTION(CALG_AGREEDKEY_ANY); + CIPHEROPTION(CALG_AGREEDKEY_ANY), #endif #ifdef CALG_HUGHES_MD5 - CIPHEROPTION(CALG_HUGHES_MD5); + CIPHEROPTION(CALG_HUGHES_MD5), #endif - CIPHEROPTION(CALG_SKIPJACK); + CIPHEROPTION(CALG_SKIPJACK), #ifdef CALG_TEK - CIPHEROPTION(CALG_TEK); + CIPHEROPTION(CALG_TEK), #endif - CIPHEROPTION(CALG_CYLINK_MEK); - CIPHEROPTION(CALG_SSL3_SHAMD5); + CIPHEROPTION(CALG_CYLINK_MEK), + CIPHEROPTION(CALG_SSL3_SHAMD5), #ifdef CALG_SSL3_MASTER - CIPHEROPTION(CALG_SSL3_MASTER); + CIPHEROPTION(CALG_SSL3_MASTER), #endif #ifdef CALG_SCHANNEL_MASTER_HASH - CIPHEROPTION(CALG_SCHANNEL_MASTER_HASH); + CIPHEROPTION(CALG_SCHANNEL_MASTER_HASH), #endif #ifdef CALG_SCHANNEL_MAC_KEY - CIPHEROPTION(CALG_SCHANNEL_MAC_KEY); + CIPHEROPTION(CALG_SCHANNEL_MAC_KEY), #endif #ifdef CALG_SCHANNEL_ENC_KEY - CIPHEROPTION(CALG_SCHANNEL_ENC_KEY); + CIPHEROPTION(CALG_SCHANNEL_ENC_KEY), #endif #ifdef CALG_PCT1_MASTER - CIPHEROPTION(CALG_PCT1_MASTER); + CIPHEROPTION(CALG_PCT1_MASTER), #endif #ifdef CALG_SSL2_MASTER - CIPHEROPTION(CALG_SSL2_MASTER); + CIPHEROPTION(CALG_SSL2_MASTER), #endif #ifdef CALG_TLS1_MASTER - CIPHEROPTION(CALG_TLS1_MASTER); + CIPHEROPTION(CALG_TLS1_MASTER), #endif #ifdef CALG_RC5 - CIPHEROPTION(CALG_RC5); + CIPHEROPTION(CALG_RC5), #endif #ifdef CALG_HMAC - CIPHEROPTION(CALG_HMAC); + CIPHEROPTION(CALG_HMAC), #endif #ifdef CALG_TLS1PRF - CIPHEROPTION(CALG_TLS1PRF); + CIPHEROPTION(CALG_TLS1PRF), #endif #ifdef CALG_HASH_REPLACE_OWF - CIPHEROPTION(CALG_HASH_REPLACE_OWF); + CIPHEROPTION(CALG_HASH_REPLACE_OWF), #endif #ifdef CALG_AES_128 - CIPHEROPTION(CALG_AES_128); + CIPHEROPTION(CALG_AES_128), #endif #ifdef CALG_AES_192 - CIPHEROPTION(CALG_AES_192); + CIPHEROPTION(CALG_AES_192), #endif #ifdef CALG_AES_256 - CIPHEROPTION(CALG_AES_256); + CIPHEROPTION(CALG_AES_256), #endif #ifdef CALG_AES - CIPHEROPTION(CALG_AES); + CIPHEROPTION(CALG_AES), #endif #ifdef CALG_SHA_256 - CIPHEROPTION(CALG_SHA_256); + CIPHEROPTION(CALG_SHA_256), #endif #ifdef CALG_SHA_384 - CIPHEROPTION(CALG_SHA_384); + CIPHEROPTION(CALG_SHA_384), #endif #ifdef CALG_SHA_512 - CIPHEROPTION(CALG_SHA_512); + CIPHEROPTION(CALG_SHA_512), #endif #ifdef CALG_ECDH - CIPHEROPTION(CALG_ECDH); + CIPHEROPTION(CALG_ECDH), #endif #ifdef CALG_ECMQV - CIPHEROPTION(CALG_ECMQV); + CIPHEROPTION(CALG_ECMQV), #endif #ifdef CALG_ECDSA - CIPHEROPTION(CALG_ECDSA); + CIPHEROPTION(CALG_ECDSA), #endif #ifdef CALG_ECDH_EPHEM - CIPHEROPTION(CALG_ECDH_EPHEM); + CIPHEROPTION(CALG_ECDH_EPHEM), #endif - return 0; + {NULL, 0}, +}; + +static int +get_alg_id_by_name(char *name) +{ + char *nameEnd = strchr(name, ':'); + size_t n = nameEnd ? (size_t)(nameEnd - name) : strlen(name); + int i; + + for(i = 0; algs[i].name; i++) { + if((n == strlen(algs[i].name) && !strncmp(algs[i].name, name, n))) + return algs[i].id; + } + return 0; /* not found */ } #define NUM_CIPHERS 47 /* There are 47 options listed above */ @@ -1201,18 +1206,18 @@ schannel_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) /* The first four bytes will be an unsigned int indicating number of bytes of data in the rest of the buffer. */ extension_len = (unsigned int *)(void *)(&alpn_buffer[cur]); - cur += sizeof(unsigned int); + cur += (int)sizeof(unsigned int); /* The next four bytes are an indicator that this buffer will contain ALPN data, as opposed to NPN, for example. */ *(unsigned int *)(void *)&alpn_buffer[cur] = SecApplicationProtocolNegotiationExt_ALPN; - cur += sizeof(unsigned int); + cur += (int)sizeof(unsigned int); /* The next two bytes will be an unsigned short indicating the number of bytes used to list the preferred protocols. */ list_len = (unsigned short*)(void *)(&alpn_buffer[cur]); - cur += sizeof(unsigned short); + cur += (int)sizeof(unsigned short); list_start_index = cur; @@ -1225,7 +1230,9 @@ schannel_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) cur += proto.len; *list_len = curlx_uitous(cur - list_start_index); - *extension_len = *list_len + sizeof(unsigned int) + sizeof(unsigned short); + *extension_len = *list_len + + (unsigned short)sizeof(unsigned int) + + (unsigned short)sizeof(unsigned short); InitSecBuffer(&inbuf, SECBUFFER_APPLICATION_PROTOCOLS, alpn_buffer, cur); InitSecBufferDesc(&inbuf_desc, &inbuf, 1); diff --git a/Utilities/cmcurl/lib/vtls/sectransp.c b/Utilities/cmcurl/lib/vtls/sectransp.c index 2e98169..7f55fb5 100644 --- a/Utilities/cmcurl/lib/vtls/sectransp.c +++ b/Utilities/cmcurl/lib/vtls/sectransp.c @@ -2150,50 +2150,39 @@ static long pem_to_der(const char *in, unsigned char **out, size_t *outlen) return sep_end - in; } +#define MAX_CERTS_SIZE (50*1024*1024) /* arbitrary - to catch mistakes */ + static int read_cert(const char *file, unsigned char **out, size_t *outlen) { int fd; - ssize_t n, len = 0, cap = 512; - unsigned char buf[512], *data; + ssize_t n; + unsigned char buf[512]; + struct dynbuf certs; + + Curl_dyn_init(&certs, MAX_CERTS_SIZE); fd = open(file, 0); if(fd < 0) return -1; - data = malloc(cap); - if(!data) { - close(fd); - return -1; - } - for(;;) { n = read(fd, buf, sizeof(buf)); + if(!n) + break; if(n < 0) { close(fd); - free(data); + Curl_dyn_free(&certs); return -1; } - else if(n == 0) { + if(Curl_dyn_addn(&certs, buf, n)) { close(fd); - break; - } - - if(len + n >= cap) { - cap *= 2; - data = Curl_saferealloc(data, cap); - if(!data) { - close(fd); - return -1; - } + return -1; } - - memcpy(data + len, buf, n); - len += n; } - data[len] = '\0'; + close(fd); - *out = data; - *outlen = len; + *out = Curl_dyn_uptr(&certs); + *outlen = Curl_dyn_len(&certs); return 0; } @@ -2202,16 +2191,18 @@ static int append_cert_to_array(struct Curl_easy *data, const unsigned char *buf, size_t buflen, CFMutableArrayRef array) { - CFDataRef certdata = CFDataCreate(kCFAllocatorDefault, buf, buflen); char *certp; CURLcode result; + SecCertificateRef cacert; + CFDataRef certdata; + + certdata = CFDataCreate(kCFAllocatorDefault, buf, buflen); if(!certdata) { failf(data, "SSL: failed to allocate array for CA certificate"); return CURLE_OUT_OF_MEMORY; } - SecCertificateRef cacert = - SecCertificateCreateWithData(kCFAllocatorDefault, certdata); + cacert = SecCertificateCreateWithData(kCFAllocatorDefault, certdata); CFRelease(certdata); if(!cacert) { failf(data, "SSL: failed to create SecCertificate from CA certificate"); @@ -2425,11 +2416,15 @@ static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data, do { SecTrustRef trust; - OSStatus ret = SSLCopyPeerTrust(ctx, &trust); + OSStatus ret; + SecKeyRef keyRef; + OSStatus success; + + ret = SSLCopyPeerTrust(ctx, &trust); if(ret != noErr || !trust) break; - SecKeyRef keyRef = SecTrustCopyPublicKey(trust); + keyRef = SecTrustCopyPublicKey(trust); CFRelease(trust); if(!keyRef) break; @@ -2443,8 +2438,8 @@ static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data, #elif SECTRANSP_PINNEDPUBKEY_V2 - OSStatus success = SecItemExport(keyRef, kSecFormatOpenSSL, 0, NULL, - &publicKeyBits); + success = SecItemExport(keyRef, kSecFormatOpenSSL, 0, NULL, + &publicKeyBits); CFRelease(keyRef); if(success != errSecSuccess || !publicKeyBits) break; @@ -2987,12 +2982,13 @@ static CURLcode sectransp_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data) { struct ssl_connect_data *connssl = cf->ctx; + CURLcode result; DEBUGF(LOG_CF(data, cf, "connect_step3")); /* There is no step 3! * Well, okay, let's collect server certificates, and if verbose mode is on, * let's print the details of the server certificates. */ - const CURLcode result = collect_server_cert(cf, data); + result = collect_server_cert(cf, data); if(result) return result; @@ -3237,35 +3233,6 @@ static size_t sectransp_version(char *buffer, size_t size) return msnprintf(buffer, size, "SecureTransport"); } -/* - * This function uses SSLGetSessionState to determine connection status. - * - * Return codes: - * 1 means the connection is still in place - * 0 means the connection has been closed - * -1 means the connection status is unknown - */ -static int sectransp_check_cxn(struct Curl_cfilter *cf, - struct Curl_easy *data) -{ - struct ssl_connect_data *connssl = cf->ctx; - struct ssl_backend_data *backend = connssl->backend; - OSStatus err; - SSLSessionState state; - - (void)data; - DEBUGASSERT(backend); - - if(backend->ssl_ctx) { - DEBUGF(LOG_CF(data, cf, "check connection")); - err = SSLGetSessionState(backend->ssl_ctx, &state); - if(err == noErr) - return state == kSSLConnected || state == kSSLHandshake; - return -1; - } - return 0; -} - static bool sectransp_data_pending(struct Curl_cfilter *cf, const struct Curl_easy *data) { @@ -3410,13 +3377,15 @@ static ssize_t sectransp_recv(struct Curl_cfilter *cf, DEBUGASSERT(backend); again: + *curlcode = CURLE_OK; err = SSLRead(backend->ssl_ctx, buf, buffersize, &processed); if(err != noErr) { switch(err) { case errSSLWouldBlock: /* return how much we read (if anything) */ - if(processed) + if(processed) { return (ssize_t)processed; + } *curlcode = CURLE_AGAIN; return -1L; break; @@ -3428,7 +3397,7 @@ static ssize_t sectransp_recv(struct Curl_cfilter *cf, case errSSLClosedGraceful: case errSSLClosedNoNotify: *curlcode = CURLE_OK; - return -1L; + return 0; break; /* The below is errSSLPeerAuthCompleted; it's not defined in @@ -3439,8 +3408,10 @@ static ssize_t sectransp_recv(struct Curl_cfilter *cf, CURLcode result = verify_cert(cf, data, conn_config->CAfile, conn_config->ca_info_blob, backend->ssl_ctx); - if(result) - return result; + if(result) { + *curlcode = result; + return -1; + } } goto again; default: @@ -3477,7 +3448,7 @@ const struct Curl_ssl Curl_ssl_sectransp = { Curl_none_init, /* init */ Curl_none_cleanup, /* cleanup */ sectransp_version, /* version */ - sectransp_check_cxn, /* check_cxn */ + Curl_none_check_cxn, /* check_cxn */ sectransp_shutdown, /* shutdown */ sectransp_data_pending, /* data_pending */ sectransp_random, /* random */ diff --git a/Utilities/cmcurl/lib/vtls/vtls.c b/Utilities/cmcurl/lib/vtls/vtls.c index 15f6844..144e6ee 100644 --- a/Utilities/cmcurl/lib/vtls/vtls.c +++ b/Utilities/cmcurl/lib/vtls/vtls.c @@ -1604,16 +1604,11 @@ static CURLcode ssl_cf_cntrl(struct Curl_cfilter *cf, struct Curl_easy *data, int event, int arg1, void *arg2) { - struct ssl_connect_data *connssl = cf->ctx; struct cf_call_data save; (void)arg1; (void)arg2; switch(event) { - case CF_CTRL_CONN_REPORT_STATS: - if(cf->sockindex == FIRSTSOCKET && !Curl_ssl_cf_is_proxy(cf)) - Curl_pgrsTimeWas(data, TIMER_APPCONNECT, connssl->handshake_done); - break; case CF_CTRL_DATA_ATTACH: if(Curl_ssl->attach_data) { CF_DATA_SAVE(save, cf, data); @@ -1634,10 +1629,32 @@ static CURLcode ssl_cf_cntrl(struct Curl_cfilter *cf, return CURLE_OK; } -static bool cf_ssl_is_alive(struct Curl_cfilter *cf, struct Curl_easy *data) +static CURLcode ssl_cf_query(struct Curl_cfilter *cf, + struct Curl_easy *data, + int query, int *pres1, void *pres2) +{ + struct ssl_connect_data *connssl = cf->ctx; + + switch(query) { + case CF_QUERY_TIMER_APPCONNECT: { + struct curltime *when = pres2; + if(cf->connected && !Curl_ssl_cf_is_proxy(cf)) + *when = connssl->handshake_done; + return CURLE_OK; + } + default: + break; + } + return cf->next? + cf->next->cft->query(cf->next, data, query, pres1, pres2) : + CURLE_UNKNOWN_OPTION; +} + +static bool cf_ssl_is_alive(struct Curl_cfilter *cf, struct Curl_easy *data, + bool *input_pending) { struct cf_call_data save; - bool result; + int result; /* * This function tries to determine connection status. * @@ -1647,9 +1664,20 @@ static bool cf_ssl_is_alive(struct Curl_cfilter *cf, struct Curl_easy *data) * -1 means the connection status is unknown */ CF_DATA_SAVE(save, cf, data); - result = Curl_ssl->check_cxn(cf, data) != 0; + result = Curl_ssl->check_cxn(cf, data); CF_DATA_RESTORE(cf, save); - return result; + if(result > 0) { + *input_pending = TRUE; + return TRUE; + } + if(result == 0) { + *input_pending = FALSE; + return FALSE; + } + /* ssl backend does not know */ + return cf->next? + cf->next->cft->is_alive(cf->next, data, input_pending) : + FALSE; /* pessimistic in absence of data */ } struct Curl_cftype Curl_cft_ssl = { @@ -1667,7 +1695,7 @@ struct Curl_cftype Curl_cft_ssl = { ssl_cf_cntrl, cf_ssl_is_alive, Curl_cf_def_conn_keep_alive, - Curl_cf_def_query, + ssl_cf_query, }; struct Curl_cftype Curl_cft_ssl_proxy = { diff --git a/Utilities/cmcurl/lib/vtls/wolfssl.c b/Utilities/cmcurl/lib/vtls/wolfssl.c index 2e57899..ac68eab 100644 --- a/Utilities/cmcurl/lib/vtls/wolfssl.c +++ b/Utilities/cmcurl/lib/vtls/wolfssl.c @@ -94,6 +94,7 @@ struct ssl_backend_data { SSL_CTX* ctx; SSL* handle; + CURLcode io_result; /* result of last BIO cfilter operation */ }; #ifdef OPENSSL_EXTRA @@ -279,12 +280,16 @@ static long bio_cf_ctrl(WOLFSSL_BIO *bio, int cmd, long num, void *ptr) static int bio_cf_out_write(WOLFSSL_BIO *bio, const char *buf, int blen) { struct Curl_cfilter *cf = wolfSSL_BIO_get_data(bio); + struct ssl_connect_data *connssl = cf->ctx; struct Curl_easy *data = CF_DATA_CURRENT(cf); ssize_t nwritten; CURLcode result = CURLE_OK; DEBUGASSERT(data); nwritten = Curl_conn_cf_send(cf->next, data, buf, blen, &result); + connssl->backend->io_result = result; + DEBUGF(LOG_CF(data, cf, "bio_write(len=%d) -> %zd, %d", + blen, nwritten, result)); wolfSSL_BIO_clear_retry_flags(bio); if(nwritten < 0 && CURLE_AGAIN == result) BIO_set_retry_read(bio); @@ -294,6 +299,7 @@ static int bio_cf_out_write(WOLFSSL_BIO *bio, const char *buf, int blen) static int bio_cf_in_read(WOLFSSL_BIO *bio, char *buf, int blen) { struct Curl_cfilter *cf = wolfSSL_BIO_get_data(bio); + struct ssl_connect_data *connssl = cf->ctx; struct Curl_easy *data = CF_DATA_CURRENT(cf); ssize_t nread; CURLcode result = CURLE_OK; @@ -304,6 +310,9 @@ static int bio_cf_in_read(WOLFSSL_BIO *bio, char *buf, int blen) return 0; nread = Curl_conn_cf_recv(cf->next, data, buf, blen, &result); + connssl->backend->io_result = result; + DEBUGF(LOG_CF(data, cf, "bio_read(len=%d) -> %zd, %d", + blen, nread, result)); wolfSSL_BIO_clear_retry_flags(bio); if(nread < 0 && CURLE_AGAIN == result) BIO_set_retry_read(bio); @@ -789,6 +798,9 @@ wolfssl_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data) } } #endif + else if(backend->io_result == CURLE_AGAIN) { + return CURLE_OK; + } else { failf(data, "SSL_connect failed with error %d: %s", detail, ERR_error_string(detail, error_buffer)); @@ -948,7 +960,6 @@ static ssize_t wolfssl_send(struct Curl_cfilter *cf, ERR_clear_error(); rc = SSL_write(backend->handle, mem, memlen); - if(rc <= 0) { int err = SSL_get_error(backend->handle, rc); @@ -956,9 +967,17 @@ static ssize_t wolfssl_send(struct Curl_cfilter *cf, case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_WRITE: /* there's data pending, re-invoke SSL_write() */ + DEBUGF(LOG_CF(data, cf, "wolfssl_send(len=%zu) -> AGAIN", len)); *curlcode = CURLE_AGAIN; return -1; default: + if(backend->io_result == CURLE_AGAIN) { + DEBUGF(LOG_CF(data, cf, "wolfssl_send(len=%zu) -> AGAIN", len)); + *curlcode = CURLE_AGAIN; + return -1; + } + DEBUGF(LOG_CF(data, cf, "wolfssl_send(len=%zu) -> %d, %d", + len, rc, err)); failf(data, "SSL write: %s, errno %d", ERR_error_string(err, error_buffer), SOCKERRNO); @@ -966,6 +985,7 @@ static ssize_t wolfssl_send(struct Curl_cfilter *cf, return -1; } } + DEBUGF(LOG_CF(data, cf, "wolfssl_send(len=%zu) -> %d", len, rc)); return rc; } @@ -995,19 +1015,19 @@ static void wolfssl_close(struct Curl_cfilter *cf, struct Curl_easy *data) static ssize_t wolfssl_recv(struct Curl_cfilter *cf, struct Curl_easy *data, - char *buf, - size_t buffersize, + char *buf, size_t blen, CURLcode *curlcode) { struct ssl_connect_data *connssl = cf->ctx; struct ssl_backend_data *backend = connssl->backend; char error_buffer[WOLFSSL_MAX_ERROR_SZ]; - int buffsize = (buffersize > (size_t)INT_MAX) ? INT_MAX : (int)buffersize; + int buffsize = (blen > (size_t)INT_MAX) ? INT_MAX : (int)blen; int nread; DEBUGASSERT(backend); ERR_clear_error(); + *curlcode = CURLE_OK; nread = SSL_read(backend->handle, buf, buffsize); @@ -1016,22 +1036,31 @@ static ssize_t wolfssl_recv(struct Curl_cfilter *cf, switch(err) { case SSL_ERROR_ZERO_RETURN: /* no more data */ - break; + DEBUGF(LOG_CF(data, cf, "wolfssl_recv(len=%zu) -> CLOSED", blen)); + *curlcode = CURLE_OK; + return 0; case SSL_ERROR_NONE: /* FALLTHROUGH */ case SSL_ERROR_WANT_READ: /* FALLTHROUGH */ case SSL_ERROR_WANT_WRITE: /* there's data pending, re-invoke SSL_read() */ + DEBUGF(LOG_CF(data, cf, "wolfssl_recv(len=%zu) -> AGAIN", blen)); *curlcode = CURLE_AGAIN; return -1; default: + if(backend->io_result == CURLE_AGAIN) { + DEBUGF(LOG_CF(data, cf, "wolfssl_recv(len=%zu) -> AGAIN", blen)); + *curlcode = CURLE_AGAIN; + return -1; + } failf(data, "SSL read: %s, errno %d", ERR_error_string(err, error_buffer), SOCKERRNO); *curlcode = CURLE_RECV_ERROR; return -1; } } + DEBUGF(LOG_CF(data, cf, "wolfssl_recv(len=%zu) -> %d", blen, nread)); return nread; } diff --git a/Utilities/cmcurl/lib/vtls/x509asn1.c b/Utilities/cmcurl/lib/vtls/x509asn1.c index 39e4fb3..c298200 100644 --- a/Utilities/cmcurl/lib/vtls/x509asn1.c +++ b/Utilities/cmcurl/lib/vtls/x509asn1.c @@ -1118,7 +1118,7 @@ CURLcode Curl_extract_certinfo(struct Curl_easy *data, for(ccp = cert.version.beg; ccp < cert.version.end; ccp++) version = (version << 8) | *(const unsigned char *) ccp; if(data->set.ssl.certinfo) { - ccp = curl_maprintf("%lx", version); + ccp = curl_maprintf("%x", version); if(!ccp) return CURLE_OUT_OF_MEMORY; result = Curl_ssl_push_certinfo(data, certnum, "Version", ccp); @@ -1127,7 +1127,7 @@ CURLcode Curl_extract_certinfo(struct Curl_easy *data, return result; } if(!certnum) - infof(data, " Version: %lu (0x%lx)", version + 1, version); + infof(data, " Version: %u (0x%x)", version + 1, version); /* Serial number. */ ccp = ASN1tostr(&cert.serialNumber, 0); diff --git a/Utilities/cmcurl/lib/wildcard.c b/Utilities/cmcurl/lib/wildcard.c deleted file mode 100644 index 3b81c7a..0000000 --- a/Utilities/cmcurl/lib/wildcard.c +++ /dev/null @@ -1,75 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.se/docs/copyright.html. - * - * You may opt to use, copy, modify, merge, publish, distribute and/or sell - * copies of the Software, and permit persons to whom the Software is - * furnished to do so, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - * SPDX-License-Identifier: curl - * - ***************************************************************************/ - -#include "curl_setup.h" - -#ifndef CURL_DISABLE_FTP - -#include "wildcard.h" -#include "llist.h" -#include "fileinfo.h" -/* The last 3 #include files should be in this order */ -#include "curl_printf.h" -#include "curl_memory.h" -#include "memdebug.h" - -static void fileinfo_dtor(void *user, void *element) -{ - (void)user; - Curl_fileinfo_cleanup(element); -} - -CURLcode Curl_wildcard_init(struct WildcardData *wc) -{ - Curl_llist_init(&wc->filelist, fileinfo_dtor); - wc->state = CURLWC_INIT; - - return CURLE_OK; -} - -void Curl_wildcard_dtor(struct WildcardData *wc) -{ - if(!wc) - return; - - if(wc->dtor) { - wc->dtor(wc->protdata); - wc->dtor = ZERO_NULL; - wc->protdata = NULL; - } - DEBUGASSERT(wc->protdata == NULL); - - Curl_llist_destroy(&wc->filelist, NULL); - - - free(wc->path); - wc->path = NULL; - free(wc->pattern); - wc->pattern = NULL; - - wc->customptr = NULL; - wc->state = CURLWC_INIT; -} - -#endif /* if disabled */ diff --git a/Utilities/cmcurl/lib/wildcard.h b/Utilities/cmcurl/lib/wildcard.h deleted file mode 100644 index 9dccab0..0000000 --- a/Utilities/cmcurl/lib/wildcard.h +++ /dev/null @@ -1,70 +0,0 @@ -#ifndef HEADER_CURL_WILDCARD_H -#define HEADER_CURL_WILDCARD_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.se/docs/copyright.html. - * - * You may opt to use, copy, modify, merge, publish, distribute and/or sell - * copies of the Software, and permit persons to whom the Software is - * furnished to do so, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - * SPDX-License-Identifier: curl - * - ***************************************************************************/ - -#include "curl_setup.h" - -#ifndef CURL_DISABLE_FTP -#include <curl/curl.h> -#include "llist.h" - -/* list of wildcard process states */ -typedef enum { - CURLWC_CLEAR = 0, - CURLWC_INIT = 1, - CURLWC_MATCHING, /* library is trying to get list of addresses for - downloading */ - CURLWC_DOWNLOADING, - CURLWC_CLEAN, /* deallocate resources and reset settings */ - CURLWC_SKIP, /* skip over concrete file */ - CURLWC_ERROR, /* error cases */ - CURLWC_DONE /* if is wildcard->state == CURLWC_DONE wildcard loop - will end */ -} wildcard_states; - -typedef void (*wildcard_dtor)(void *ptr); - -/* struct keeping information about wildcard download process */ -struct WildcardData { - wildcard_states state; - char *path; /* path to the directory, where we trying wildcard-match */ - char *pattern; /* wildcard pattern */ - struct Curl_llist filelist; /* llist with struct Curl_fileinfo */ - void *protdata; /* pointer to protocol specific temporary data */ - wildcard_dtor dtor; - void *customptr; /* for CURLOPT_CHUNK_DATA pointer */ -}; - -CURLcode Curl_wildcard_init(struct WildcardData *wc); -void Curl_wildcard_dtor(struct WildcardData *wc); - -struct Curl_easy; - -#else -/* FTP is disabled */ -#define Curl_wildcard_dtor(x) -#endif - -#endif /* HEADER_CURL_WILDCARD_H */ diff --git a/Utilities/cmcurl/lib/ws.c b/Utilities/cmcurl/lib/ws.c index 0fc5e56..e8495dc 100644 --- a/Utilities/cmcurl/lib/ws.c +++ b/Utilities/cmcurl/lib/ws.c @@ -166,10 +166,6 @@ CURLcode Curl_ws_accept(struct Curl_easy *data, } k->upgr101 = UPGR101_RECEIVED; - if(data->set.connect_only) - /* switch off non-blocking sockets */ - (void)curlx_nonblock(conn->sock[FIRSTSOCKET], FALSE); - return result; } @@ -750,9 +746,6 @@ CURLcode Curl_ws_disconnect(struct Curl_easy *data, (void)data; (void)dead_connection; Curl_dyn_free(&wsc->early); - - /* make sure this is non-blocking to avoid getting stuck in shutdown */ - (void)curlx_nonblock(conn->sock[FIRSTSOCKET], TRUE); return CURLE_OK; } diff --git a/doxygen.config b/doxygen.config deleted file mode 100644 index 82add73..0000000 --- a/doxygen.config +++ /dev/null @@ -1,697 +0,0 @@ -# Doxyfile 1.1.4-20000625 - -# This file describes the settings to be used by doxygen for a project -# -# All text after a hash (#) is considered a comment and will be ignored -# The format is: -# TAG = value [value, ...] -# Values that contain spaces should be placed between quotes (" ") - -#--------------------------------------------------------------------------- -# General configuration options -#--------------------------------------------------------------------------- - -# The PROJECT_NAME tag is a single word (or a sequence of words surrounded -# by quotes) that should identify the project. - -PROJECT_NAME = CMAKE - -# The PROJECT_NUMBER tag can be used to enter a project or revision number. -# This could be handy for archiving the generated documentation or -# if some version control system is used. - -PROJECT_NUMBER = 0.0.1 - -# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) -# base path where the generated documentation will be put. -# If a relative path is entered, it will be relative to the location -# where doxygen was started. If left blank the current directory will be used. - -OUTPUT_DIRECTORY = ./Doxygen - -# The OUTPUT_LANGUAGE tag is used to specify the language in which all -# documentation generated by doxygen is written. Doxygen will use this -# information to generate all constant output in the proper language. -# The default language is English, other supported languages are: -# Dutch, French, Italian, Czech, Swedish, German, Finnish, Japanese, -# Spanish and Russian - -OUTPUT_LANGUAGE = English - -# The DISABLE_INDEX tag can be used to turn on/off the condensed index at -# top of each HTML page. The value NO (the default) enables the index and -# the value YES disables it. - -DISABLE_INDEX = NO - -# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in -# documentation are documented, even if no documentation was available. -# Private class members and static file members will be hidden unless -# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES - -EXTRACT_ALL = YES - -# If the EXTRACT_PRIVATE tag is set to YES all private members of a class -# will be included in the documentation. - -EXTRACT_PRIVATE = NO - -# If the EXTRACT_STATIC tag is set to YES all static members of a file -# will be included in the documentation. - -EXTRACT_STATIC = YES - -# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all -# undocumented members of documented classes, files or namespaces. -# If set to NO (the default) these members will be included in the -# various overviews, but no documentation section is generated. -# This option has no effect if EXTRACT_ALL is enabled. - -HIDE_UNDOC_MEMBERS = NO - -# If the HIDE_UNDOC_CLASSESS tag is set to YES, Doxygen will hide all -# undocumented classes that are normally visible in the class hierarchy. -# If set to NO (the default) these class will be included in the various -# overviews. This option has no effect if EXTRACT_ALL is enabled. - -HIDE_UNDOC_CLASSES = NO - -# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will -# include brief member descriptions after the members that are listed in -# the file and class documentation (similar to JavaDoc). -# Set to NO to disable this. - -BRIEF_MEMBER_DESC = YES - -# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend -# the brief description of a member or function before the detailed description. -# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the -# brief descriptions will be completely suppressed. - -REPEAT_BRIEF = YES - -# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then -# Doxygen will generate a detailed section even if there is only a brief -# description. - -ALWAYS_DETAILED_SEC = NO - -# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full -# path before files name in the file list and in the header files. If set -# to NO the shortest path that makes the file name unique will be used. - -FULL_PATH_NAMES = NO - -# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag -# can be used to strip a user defined part of the path. Stripping is -# only done if one of the specified strings matches the left-hand part of -# the path. - -STRIP_FROM_PATH = - -# The INTERNAL_DOCS tag determines if documentation -# that is typed after a \internal command is included. If the tag is set -# to NO (the default) then the documentation will be excluded. -# Set it to YES to include the internal documentation. - -INTERNAL_DOCS = NO - -# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will -# generate a class diagram (in Html and LaTeX) for classes with base or -# super classes. Setting the tag to NO turns the diagrams off. - -CLASS_DIAGRAMS = YES - -# If the SOURCE_BROWSER tag is set to YES then a list of source files will -# be generated. Documented entities will be cross-referenced with these sources. - -SOURCE_BROWSER = YES - -# Setting the INLINE_SOURCES tag to YES will include the body -# of functions and classes directly in the documentation. - -INLINE_SOURCES = NO - -# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct -# doxygen to hide any special comment blocks from generated source code -# fragments. Normal C and C++ comments will always remain visible. - -STRIP_CODE_COMMENTS = YES - -# If the CASE_SENSE_NAMES tag is set to NO (the default) then Doxygen -# will only generate file names in lower case letters. If set to -# YES upper case letters are also allowed. This is useful if you have -# classes or files whose names only differ in case and if your file system -# supports case sensitive file names. - -CASE_SENSE_NAMES = YES - -# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen -# will show members with their full class and namespace scopes in the -# documentation. If set to YES the scope will be hidden. - -HIDE_SCOPE_NAMES = NO - -# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen -# will generate a verbatim copy of the header file for each class for -# which an include is specified. Set to NO to disable this. - -VERBATIM_HEADERS = YES - -# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen -# will put list of the files that are included by a file in the documentation -# of that file. - -SHOW_INCLUDE_FILES = YES - -# If the JAVADOC_AUTOBRIEF tag is set to YES (the default) then Doxygen -# will interpret the first line (until the first dot) of a JavaDoc-style -# comment as the brief description. If set to NO, the Javadoc-style will -# behave just like the Qt-style comments. - -JAVADOC_AUTOBRIEF = NO - -# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented -# member inherits the documentation from any documented member that it -# reimplements. - -INHERIT_DOCS = YES - -# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] -# is inserted in the documentation for inline members. - -INLINE_INFO = YES - -# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen -# will sort the (detailed) documentation of file and class members -# alphabetically by member name. If set to NO the members will appear in -# declaration order. - -SORT_MEMBER_DOCS = YES - -# The TAB_SIZE tag can be used to set the number of spaces in a tab. -# Doxygen uses this value to replace tabs by spaces in code fragments. - -TAB_SIZE = 8 - -# The ENABLE_SECTIONS tag can be used to enable conditional -# documentation sections, marked by \if sectionname ... \endif. - -ENABLED_SECTIONS = - -#--------------------------------------------------------------------------- -# configuration options related to warning and progress messages -#--------------------------------------------------------------------------- - -# The QUIET tag can be used to turn on/off the messages that are generated -# by doxygen. Possible values are YES and NO. If left blank NO is used. - -QUIET = NO - -# The WARNINGS tag can be used to turn on/off the warning messages that are -# generated by doxygen. Possible values are YES and NO. If left blank -# NO is used. - -WARNINGS = YES - -# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings -# for undocumented members. If EXTRACT_ALL is set to YES then this flag will -# automatically be disabled. - -WARN_IF_UNDOCUMENTED = YES - -# The WARN_FORMAT tag determines the format of the warning messages that -# doxygen can produce. The string should contain the $file, $line, and $text -# tags, which will be replaced by the file and line number from which the -# warning originated and the warning text. - -WARN_FORMAT = "$file:$line: $text" - -#--------------------------------------------------------------------------- -# configuration options related to the input files -#--------------------------------------------------------------------------- - -# The INPUT tag can be used to specify the files and/or directories that contain -# documented source files. You may enter file names like "myfile.cpp" or -# directories like "/usr/src/myproject". Separate the files or directories -# with spaces. - -INPUT = "Source" - -# If the value of the INPUT tag contains directories, you can use the -# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp -# and *.h) to filter out the source-files in the directories. If left -# blank all files are included. - -FILE_PATTERNS = *.h *.txx *.cxx - -# The RECURSIVE tag can be used to turn specify whether or not subdirectories -# should be searched for input files as well. Possible values are YES and NO. -# If left blank NO is used. - -RECURSIVE = YES - -# The EXCLUDE tag can be used to specify files and/or directories that should -# excluded from the INPUT source files. This way you can easily exclude a -# subdirectory from a directory tree whose root is specified with the INPUT tag. - -EXCLUDE = - -# If the value of the INPUT tag contains directories, you can use the -# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude -# certain files from those directories. - -EXCLUDE_PATTERNS = - -# The EXAMPLE_PATH tag can be used to specify one or more files or -# directories that contain example code fragments that are included (see -# the \include command). - -EXAMPLE_PATH = - -# If the value of the EXAMPLE_PATH tag contains directories, you can use the -# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp -# and *.h) to filter out the source-files in the directories. If left -# blank all files are included. - -EXAMPLE_PATTERNS = - -# The IMAGE_PATH tag can be used to specify one or more files or -# directories that contain image that are included in the documentation (see -# the \image command). - -IMAGE_PATH = - -# The INPUT_FILTER tag can be used to specify a program that doxygen should -# invoke to filter for each input file. Doxygen will invoke the filter program -# by executing (via popen()) the command <filter> <input-file>, where <filter> -# is the value of the INPUT_FILTER tag, and <input-file> is the name of an -# input file. Doxygen will then use the output that the filter program writes -# to standard output. - -INPUT_FILTER = - -#--------------------------------------------------------------------------- -# configuration options related to the alphabetical class index -#--------------------------------------------------------------------------- - -# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index -# of all compounds will be generated. Enable this if the project -# contains a lot of classes, structs, unions or interfaces. - -ALPHABETICAL_INDEX = YES - -# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then -# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns -# in which this list will be split (can be a number in the range [1..20]) - -COLS_IN_ALPHA_INDEX = 3 - -# In case all classes in a project start with a common prefix, all -# classes will be put under the same header in the alphabetical index. -# The IGNORE_PREFIX tag can be used to specify one or more prefixes that -# should be ignored while generating the index headers. - -IGNORE_PREFIX = - -#--------------------------------------------------------------------------- -# configuration options related to the HTML output -#--------------------------------------------------------------------------- - -# If the GENERATE_HTML tag is set to YES (the default) Doxygen will -# generate HTML output. - -GENERATE_HTML = YES - -# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `html' will be used as the default path. - -HTML_OUTPUT = html - -# The HTML_HEADER tag can be used to specify a personal HTML header for -# each generated HTML page. If it is left blank doxygen will generate a -# standard header. - -HTML_HEADER = - -# The HTML_FOOTER tag can be used to specify a personal HTML footer for -# each generated HTML page. If it is left blank doxygen will generate a -# standard footer. - -HTML_FOOTER = - -# The HTML_STYLESHEET tag can be used to specify a user defined cascading -# style sheet that is used by each HTML page. It can be used to -# fine-tune the look of the HTML output. If the tag is left blank doxygen -# will generate a default style sheet - -HTML_STYLESHEET = - -# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, -# files or namespaces will be aligned in HTML using tables. If set to -# NO a bullet list will be used. - -HTML_ALIGN_MEMBERS = YES - -# If the GENERATE_HTMLHELP tag is set to YES, additional index files -# will be generated that can be used as input for tools like the -# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) -# of the generated HTML documentation. - -GENERATE_HTMLHELP = NO - -#--------------------------------------------------------------------------- -# configuration options related to the LaTeX output -#--------------------------------------------------------------------------- - -# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will -# generate Latex output. - -GENERATE_LATEX = YES - -# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `latex' will be used as the default path. - -LATEX_OUTPUT = latex - -# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact -# LaTeX documents. This may be useful for small projects and may help to -# save some trees in general. - -COMPACT_LATEX = NO - -# The PAPER_TYPE tag can be used to set the paper type that is used -# by the printer. Possible values are: a4, a4wide, letter, legal and -# executive. If left blank a4wide will be used. - -PAPER_TYPE = a4wide - -# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX -# packages that should be included in the LaTeX output. - -EXTRA_PACKAGES = - -# The LATEX_HEADER tag can be used to specify a personal LaTeX header for -# the generated latex document. The header should contain everything until -# the first chapter. If it is left blank doxygen will generate a -# standard header. Notice: only use this tag if you know what you are doing! - -LATEX_HEADER = - -# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated -# is prepared for conversion to pdf (using ps2pdf). The pdf file will -# contain links (just like the HTML output) instead of page references -# This makes the output suitable for online browsing using a pdf viewer. - -PDF_HYPERLINKS = NO - -# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. -# command to the generated LaTeX files. This will instruct LaTeX to keep -# running if errors occur, instead of asking the user for help. -# This option is also used when generating formulas in HTML. - -LATEX_BATCHMODE = NO - -#--------------------------------------------------------------------------- -# configuration options related to the RTF output -#--------------------------------------------------------------------------- - -# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output -# For now this is experimental and is disabled by default. The RTF output -# is optimised for Word 97 and may not look too pretty with other readers -# or editors. - -GENERATE_RTF = YES - -# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `rtf' will be used as the default path. - -RTF_OUTPUT = rtf - -# If the COMPACT_RTF tag is set to YES Doxygen generates more compact -# RTF documents. This may be useful for small projects and may help to -# save some trees in general. - -COMPACT_RTF = NO - -# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated -# will contain hyperlink fields. The RTF file will -# contain links (just like the HTML output) instead of page references. -# This makes the output suitable for online browsing using a WORD or other. -# programs which support those fields. -# Note: wordpad (write) and others do not support links. - -RTF_HYPERLINKS = NO - -#--------------------------------------------------------------------------- -# configuration options related to the man page output -#--------------------------------------------------------------------------- - -# If the GENERATE_MAN tag is set to YES (the default) Doxygen will -# generate man pages - -GENERATE_MAN = YES - -# The MAN_OUTPUT tag is used to specify where the man pages will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `man' will be used as the default path. - -MAN_OUTPUT = man - -# The MAN_EXTENSION tag determines the extension that is added to -# the generated man pages (default is the subroutine's section .3) - -MAN_EXTENSION = .3 - -#--------------------------------------------------------------------------- -# Configuration options related to the preprocessor -#--------------------------------------------------------------------------- - -# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will -# evaluate all C-preprocessor directives found in the sources and include -# files. - -ENABLE_PREPROCESSING = YES - -# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro -# names in the source code. If set to NO (the default) only conditional -# compilation will be performed. - -MACRO_EXPANSION = YES - -# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files -# in the INCLUDE_PATH (see below) will be search if a #include is found. - -SEARCH_INCLUDES = NO - -# The INCLUDE_PATH tag can be used to specify one or more directories that -# contain include files that are not input files but should be processed by -# the preprocessor. - -INCLUDE_PATH = - -# The PREDEFINED tag can be used to specify one or more macro names that -# are defined before the preprocessor is started (similar to the -D option of -# gcc). The argument of the tag is a list of macros of the form: name -# or name=definition (no spaces). If the definition and the = are -# omitted =1 is assumed. - -PREDEFINED = "itkNotUsed(x)="\ - "itkSetMacro(name,type)= \ - virtual void Set##name (type _arg);" \ - "itkGetMacro(name,type)= \ - virtual type Get##name ();" \ - "itkGetConstMacro(name,type)= \ - virtual type Get##name () const;" \ - "itkSetStringMacro(name)= \ - virtual void Set##name (const char* _arg);" \ - "itkGetStringMacro(name)= \ - virtual const char* Get##name () const;" \ - "itkSetClampMacro(name,type,min,max)= \ - virtual void Set##name (type _arg);" \ - "itkSetObjectMacro(name,type)= \ - virtual void Set##name (type* _arg);" \ - "itkGetObjectMacro(name,type)= \ - virtual type* Get##name ();" \ - "itkBooleanMacro(name)= \ - virtual void name##On (); \ - virtual void name##Off ();" \ - "itkSetVector2Macro(name,type)= \ - virtual void Set##name (type _arg1, type _arg2) \ - virtual void Set##name (type _arg[2]);" \ - "itkGetVector2Macro(name,type)= \ - virtual type* Get##name () const; \ - virtual void Get##name (type& _arg1, type& _arg2) const; \ - virtual void Get##name (type _arg[2]) const;" \ - "itkSetVector3Macro(name,type)= \ - virtual void Set##name (type _arg1, type _arg2, type _arg3) \ - virtual void Set##name (type _arg[3]);" \ - "itkGetVector3Macro(name,type)= \ - virtual type* Get##name () const; \ - virtual void Get##name (type& _arg1, type& _arg2, type& _arg3) const; \ - virtual void Get##name (type _arg[3]) const;" \ - "itkSetVector4Macro(name,type)= \ - virtual void Set##name (type _arg1, type _arg2, type _arg3, type _arg4) \ - virtual void Set##name (type _arg[4]);" \ - "itkGetVector4Macro(name,type)= \ - virtual type* Get##name () const; \ - virtual void Get##name (type& _arg1, type& _arg2, type& _arg3, type& _arg4) const; \ - virtual void Get##name (type _arg[4]) const;" \ - "itkSetVector6Macro(name,type)= \ - virtual void Set##name (type _arg1, type _arg2, type _arg3, type _arg4, type _arg5, type _arg6) \ - virtual void Set##name (type _arg[6]);" \ - "itkGetVector6Macro(name,type)= \ - virtual type* Get##name () const; \ - virtual void Get##name (type& _arg1, type& _arg2, type& _arg3, type& _arg4, type& _arg5, type& _arg6) const; \ - virtual void Get##name (type _arg[6]) const;" \ - "itkSetVectorMacro(name,type,count)= \ - virtual void Set##name(type data[]);" \ - "itkGetVectorMacro(name,type,count)= \ - virtual type* Get##name () const;" \ - "itkNewMacro(type)= \ - static Pointer New();" \ - "itkTypeMacro(thisClass,superclass)= \ - virtual const char *GetClassName() const;" \ - "ITK_NUMERIC_LIMITS= \ - std::numeric_limits" - -# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES -# then the macro expansion is limited to the macros specified with the -# PREDEFINED tag. - -EXPAND_ONLY_PREDEF = YES - -#--------------------------------------------------------------------------- -# Configuration::addtions related to external references -#--------------------------------------------------------------------------- - -# The TAGFILES tag can be used to specify one or more tagfiles. - -TAGFILES = - -# When a file name is specified after GENERATE_TAGFILE, doxygen will create -# a tag file that is based on the input files it reads. - -GENERATE_TAGFILE = - -# If the ALLEXTERNALS tag is set to YES all external classes will be listed -# in the class index. If set to NO only the inherited external classes -# will be listed. - -ALLEXTERNALS = NO - -# The PERL_PATH should be the absolute path and name of the perl script -# interpreter (i.e. the result of `which perl'). - -PERL_PATH = /usr/bin/perl - -#--------------------------------------------------------------------------- -# Configuration options related to the dot tool -#--------------------------------------------------------------------------- - -# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is -# available from the path. This tool is part of Graphviz, a graph visualization -# toolkit from AT&T and Lucent Bell Labs. The other options in this section -# have no effect if this option is set to NO (the default) - -HAVE_DOT = YES - -# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for each documented class showing the direct and -# indirect inheritance relations. Setting this tag to YES will force the -# the CLASS_DIAGRAMS tag to NO. - -CLASS_GRAPH = YES - -# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for each documented class showing the direct and -# indirect implementation dependencies (inheritance, containment, and -# class references variables) of the class with other documented classes. - -COLLABORATION_GRAPH = YES - -# If the ENABLE_PREPROCESSING, INCLUDE_GRAPH, and HAVE_DOT tags are set to -# YES then doxygen will generate a graph for each documented file showing -# the direct and indirect include dependencies of the file with other -# documented files. - -INCLUDE_GRAPH = YES - -# If the ENABLE_PREPROCESSING, INCLUDED_BY_GRAPH, and HAVE_DOT tags are set to -# YES then doxygen will generate a graph for each documented header file showing -# the documented files that directly or indirectly include this file - -INCLUDED_BY_GRAPH = YES - -# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen -# will graphical hierarchy of all classes instead of a textual one. - -GRAPHICAL_HIERARCHY = YES - -# The tag DOT_PATH can be used to specify the path where the dot tool can be -# found. If left blank, it is assumed the dot tool can be found on the path. - -DOT_PATH = - -# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width -# (in pixels) of the graphs generated by dot. If a graph becomes larger than -# this value, doxygen will try to truncate the graph, so that it fits within -# the specified constraint. Beware that most browsers cannot cope with very -# large images. - -MAX_DOT_GRAPH_WIDTH = 1024 - -# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height -# (in pixels) of the graphs generated by dot. If a graph becomes larger than -# this value, doxygen will try to truncate the graph, so that it fits within -# the specified constraint. Beware that most browsers cannot cope with very -# large images. - -MAX_DOT_GRAPH_HEIGHT = 1024 - -#--------------------------------------------------------------------------- -# Configuration::addtions related to the search engine -#--------------------------------------------------------------------------- - -# The SEARCHENGINE tag specifies whether or not a search engine should be -# used. If set to NO the values of all tags below this one will be ignored. - -SEARCHENGINE = NO - -# The CGI_NAME tag should be the name of the CGI script that -# starts the search engine (doxysearch) with the correct parameters. -# A script with this name will be generated by doxygen. - -CGI_NAME = search.cgi - -# The CGI_URL tag should be the absolute URL to the directory where the -# cgi binaries are located. See the documentation of your http daemon for -# details. - -CGI_URL = - -# The DOC_URL tag should be the absolute URL to the directory where the -# documentation is located. If left blank the absolute path to the -# documentation, with file:// prepended to it, will be used. - -DOC_URL = - -# The DOC_ABSPATH tag should be the absolute path to the directory where the -# documentation is located. If left blank the directory on the local machine -# will be used. - -DOC_ABSPATH = - -# The BIN_ABSPATH tag must point to the directory where the doxysearch binary -# is installed. - -BIN_ABSPATH = /usr/local/bin/ - -# The EXT_DOC_PATHS tag can be used to specify one or more paths to -# documentation generated for other projects. This allows doxysearch to search -# the documentation for these projects as well. - -EXT_DOC_PATHS = |